index.html
index.html
The frontpage for navigating to the various demo samples should be adjusted as such:
Firstly, the following adjustments are required for the src
:
- Version 1
- Version 2
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!--meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"-->
<title>Signature SDK Demo</title>
<link href="../common/style/wacom.css" rel="stylesheet" type="text/css">
<link href="/sigCaptDialog/style/sigCaptDialog.css" rel="stylesheet" type="text/css">
<link href="/node_modules/jquery-ui-dist/jquery-ui.min.css" rel="stylesheet" type="text/css">
<script src="/node_modules/jquery/dist/jquery.min.js"></script>
<script src="/node_modules/jquery-ui-dist/jquery-ui.min.js"></script>
<script src="/node_modules/jquery-ui-touch-punch/jquery.ui.touch-punch.min.js"></script>
<script src="/node_modules/clipper-lib/clipper.js"></script>
<script src="/node_modules/js-md5/build/md5.min.js"></script>
<script src="/node_modules/poly2tri/dist/poly2tri.min.js"></script>
<script src="/node_modules/long/dist/long.js"></script>
<script src="/node_modules/protobufjs/dist/protobuf.min.js"></script>
<script src="/node_modules/jszip/dist/jszip.min.js"></script>
<script src="/node_modules/gl-matrix/gl-matrix-min.js"></script>
<script src="/node_modules/rbush/rbush.min.js"></script>
<script src="/node_modules/js-ext/js-ext-min.js"></script>
<script src="/node_modules/digital-ink/digital-ink-min.js"></script>
<script src="../common/will/tools.js"></script>
<script src="/node_modules/sjcl/sjcl.js"></script>
<script src="/sigCaptDialog/libs/stu_capture/stu-sdk.min.js"></script> <!-- used to connect to STU devices -->
<script src="/sigCaptDialog/libs/stu_capture/stu_capture_encryption.js"></script> <!-- STU encryption functions -->
<script src="../common/libs/signature_sdk.js"></script> <!-- signature SDK -->
<script src="../common/libs/signature_sdk_helper.js"></script> <!-- signature SDK helper -->
<script src="/node_modules/node-forge/dist/forge.min.js"></script>
<script src="/sigCaptDialog/sigCaptDialog.js"></script>
<script src="/sigCaptDialog/stuCaptDialog.js"></script>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!--meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"-->
<title>Signature SDK Demo</title>
<link href="../common/style/wacom.css" rel="stylesheet" type="text/css">
<link href="../../sigCaptDialog/style/sigCaptDialog.css" rel="stylesheet" type="text/css">
<!-- files for connection to STU tablets devices, if you don't need to connect to STU devices you don't have to include these files -->
<script src="../common/libs/signature_sdk/stu-sdk.min.js"></script> <!-- used to connect to STU devices -->
<script src="../../sigCaptDialog/stu_capture/aes-ecb.js"></script> <!-- utility for STU encryption -->
<script src="../../sigCaptDialog/stu_capture/stu_capture_encryption.js"></script> <!-- STU encryption functions -->
<script src="../common/libs/signature_sdk/signature_sdk.js"></script> <!-- signature SDK -->
<script src="../common/signature_sdk_helper.js"></script> <!-- signature SDK helper -->
<script src="../common/browser-report.js"></script> <!-- for getting web browser information -->
<script src="../../sigCaptDialog/sigCaptDialog.js"></script>
<script src="../../sigCaptDialog/stuCaptDialog.js"></script>
Immediately afterwards, adjust the code after the <script>
tag on line 37 as such:
First, remove licence
:
- Version 1
- Version 2
<script>
const licence = "<<<licence>>>";
var mSigObj;
var documentHash;
var backgroundImage;
var sigCaptDialog
var stuCapDialog;
<script>
var mSigObj;
var documentHash;
var backgroundImage;
var sigCaptDialog
var stuCapDialog;
After var encryptionKeys
:
- Version 1
- Version 2
// This var will store the public and private keys for encryption.
// Please note that this is only a demostration, but on a production application
// for security reasons the private key should not be stored in a global variable.
var encryptionKeys;
Module.onRuntimeInitialized = _ => {
document.getElementById("version_txt").innerHTML = Module.VERSION;
if (navigator.hid) {
document.getElementById("capture_stu_btn").disabled = false;
}
document.getElementById("capture_canvas_btn").disabled = false;
document.getElementById("document").disabled = false;
document.getElementById("load_signature").disabled = false;
documentHash = new Module.Hash(Module.HashType.None);
mSigObj = new Module.SigObj();
mSigObj.setLicence(licence);
}
...
// This var will store the public and private keys for encryption.
// Please note that this is only a demostration, but on a production application
// for security reasons the private key should not be stored in a global variable.
var encryptionKeys;
//to remove 300 ms wait for second tap on touch screen
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
const captureBtn = document.getElementById("capture_canvas_btn");
captureBtn.addEventListener("touchend", function(e) {event.preventDefault(); captureBtn.click(); return false;}, false);
}, false);
}
Module.onAbort = _ => {
alert("Web browser not supported");
document.getElementById("initializeBanground").style.display = "none";
}
Module.onRuntimeInitialized = _ => {
document.getElementById("version_txt").innerHTML = Module.VERSION;
documentHash = new Module.Hash(Module.HashType.None);
mSigObj = new Module.SigObj();
// Here we need to set the licence. The easiest way is directly using
// const promise = mSigObj.setLicence(key, secret);
// however here the problem it is that we expose the key and secret publically.
// if we want to hide the licence we can get the licence from an external server.
// there is a php demo file in /common/licence_proxy.php
//const promise = mSigObj.setLicenceProxy("url from where to get the licence");
const promise = mSigObj.setLicence("key", "secret");
promise.then(value => {
if (value) {
if (navigator.hid) {
document.getElementById("capture_stu_btn").disabled = false;
}
document.getElementById("capture_canvas_btn").disabled = false;
document.getElementById("document").disabled = false;
document.getElementById("load_signature").disabled = false;
document.getElementById("initializeBanground").style.display = "none";
setDeviceName();
}
});
promise.catch(error => {
alert(error);
document.getElementById("initializeBanground").style.display = "none";
});
}
The function generateConfig
needs the following adjustments:
- Version 1
- Version 2
function generateConfig() {
const config = {};
config.useWill = document.getElementById("use_will").checked;
config.strokeSize = document.getElementById("ink_width").value;
config.strokeColor = document.getElementById("rendering_color_box").value;
config.width = document.getElementById("dialog_width").value;
config.height = document.getElementById("dialog_height").value;
config.left = document.getElementById("dialog_left").value + "px";
config.top = document.getElementById("dialog_top").value + "px";
config.centered = document.getElementById("is_centered").checked;
config.title = document.getElementById("title_text").value;
config.borderColor = document.getElementById("border_color_box").value;
config.borderWidth = document.getElementById("border_width_box").value;
config.hasTitle = document.getElementById("has_title_check").checked;
config.signatory = {visible:document.getElementById("show_signatory_check").checked,
fontFace:document.getElementById("signatory_font_type_text").value,
fontSize:parseInt(document.getElementById("signatory_font_size_text").value),
offsetX:parseInt(document.getElementById("signatory_offset_x_text").value),
offsetY:parseInt(document.getElementById("signatory_offset_y_text").value),
color:document.getElementById("signatory_color_box").value
};
config.reason = {visible:document.getElementById("show_reason_check").checked,
fontFace:document.getElementById("reason_font_type_text").value,
fontSize:parseInt(document.getElementById("reason_font_size_text").value),
offsetX:parseInt(document.getElementById("reason_offset_x_text").value),
offsetY:parseInt(document.getElementById("reason_offset_y_text").value),
color:document.getElementById("reason_color_box").value
};
config.date = {visible:document.getElementById("show_date_check").checked,
fontFace:document.getElementById("date_font_type_text").value,
fontSize:parseInt(document.getElementById("date_font_size_text").value),
offsetX:parseInt(document.getElementById("date_offset_x_text").value),
offsetY:parseInt(document.getElementById("date_offset_y_text").value),
color:document.getElementById("date_color_box").value
};
config.signingLine = {visible:document.getElementById("show_signing_line_check").checked,
left:parseInt(document.getElementById("signing_line_left_text").value),
right:parseInt(document.getElementById("signing_line_right_text").value),
width:parseInt(document.getElementById("signing_line_width_text").value),
offsetY:parseInt(document.getElementById("signing_line_offset_y_text").value),
color:document.getElementById("signing_line_color_box").value
};
config.buttonsFont = document.getElementById("button_font_type").value;
config.buttons = [];
const fields = document.getElementById("button_list_div").getElementsByTagName("fieldset");
for (var i=0; i<fields.length; i++) {
config.buttons.push({text:fields[i].elements.namedItem("button_text").value,
textColor:fields[i].elements.namedItem("button_text_color").value,
backgroundColor:fields[i].elements.namedItem("button_background_color").value,
borderColor:fields[i].elements.namedItem("button_border_color").value,
borderWidth:parseInt(fields[i].elements.namedItem("button_border_width").value),
onClick:eval(fields[i].elements.namedItem("button_action").value)});
}
if (!document.getElementById("shows_as_dialog").checked) {
config.attachTo = "captureDiv";
}
const comboSizeModes = document.getElementById("stu_fit_mode");
config.sizeMode = comboSizeModes.options[comboSizeModes.selectedIndex].value;
config.modal = document.getElementById("shows_modal").checked;
config.draggable = document.getElementById("is_draggable").checked;
const comboTools = document.getElementById("inking_tool");
const inkColor = document.getElementById("rendering_color_box").value;
if (document.getElementById("use_will").checked) {
config.will = {tool:tools[comboTools.options[comboTools.selectedIndex].value], color:inkColor};
}
const comboBackgroundMode = document.getElementById("background_image_mode");
config.background = {color:document.getElementById("background_color_box").value,
alpha:document.getElementById("background_opacity").value*0.01,
mode:comboBackgroundMode.options[comboBackgroundMode.selectedIndex].value};
if ((document.getElementById("put_background_image").checked) && (backgroundImage)) {
config.background.image = backgroundImage;
}
if (document.getElementById("enable_timeout").checked) {
config.timeOut = {enabled:true};
config.timeOut.time = parseInt(document.getElementById("timeOutValue").value);
config.timeOut.onTimeOut = timeOutCallback;
}
config.minTimeOnSurface = parseInt(document.getElementById("minTimeOnSurface").value);
return config;
}
function generateConfig() {
const config = {};
config.strokeSize = parseInt(document.getElementById("ink_width").value);
config.strokeColor = document.getElementById("rendering_color_box").value;
config.width = document.getElementById("dialog_width").value;
config.height = document.getElementById("dialog_height").value;
config.left = document.getElementById("dialog_left").value + "px";
config.top = document.getElementById("dialog_top").value + "px";
config.centered = document.getElementById("is_centered").checked;
config.title = document.getElementById("title_text").value;
config.borderColor = document.getElementById("border_color_box").value;
config.borderWidth = document.getElementById("border_width_box").value;
config.hasTitle = document.getElementById("has_title_check").checked;
config.signatory = {visible:document.getElementById("show_signatory_check").checked,
fontFace:document.getElementById("signatory_font_type_text").value,
fontSize:parseInt(document.getElementById("signatory_font_size_text").value),
offsetX:parseInt(document.getElementById("signatory_offset_x_text").value),
offsetY:parseInt(document.getElementById("signatory_offset_y_text").value),
color:document.getElementById("signatory_color_box").value
};
config.reason = {visible:document.getElementById("show_reason_check").checked,
fontFace:document.getElementById("reason_font_type_text").value,
fontSize:parseInt(document.getElementById("reason_font_size_text").value),
offsetX:parseInt(document.getElementById("reason_offset_x_text").value),
offsetY:parseInt(document.getElementById("reason_offset_y_text").value),
color:document.getElementById("reason_color_box").value
};
config.date = {visible:document.getElementById("show_date_check").checked,
fontFace:document.getElementById("date_font_type_text").value,
fontSize:parseInt(document.getElementById("date_font_size_text").value),
offsetX:parseInt(document.getElementById("date_offset_x_text").value),
offsetY:parseInt(document.getElementById("date_offset_y_text").value),
color:document.getElementById("date_color_box").value
};
config.signingLine = {visible:document.getElementById("show_signing_line_check").checked,
left:parseInt(document.getElementById("signing_line_left_text").value),
right:parseInt(document.getElementById("signing_line_right_text").value),
width:parseInt(document.getElementById("signing_line_width_text").value),
offsetY:parseInt(document.getElementById("signing_line_offset_y_text").value),
color:document.getElementById("signing_line_color_box").value
};
config.buttonsFont = document.getElementById("button_font_type").value;
config.buttons = [];
const fields = document.getElementById("button_list_div").getElementsByTagName("fieldset");
for (var i=0; i<fields.length; i++) {
config.buttons.push({text:fields[i].elements.namedItem("button_text").value,
textColor:fields[i].elements.namedItem("button_text_color").value,
backgroundColor:fields[i].elements.namedItem("button_background_color").value,
borderColor:fields[i].elements.namedItem("button_border_color").value,
borderWidth:parseInt(fields[i].elements.namedItem("button_border_width").value),
onClick:eval(fields[i].elements.namedItem("button_action").value)});
}
if (!document.getElementById("shows_as_dialog").checked) {
config.attachTo = "captureDiv";
}
const comboSizeModes = document.getElementById("stu_fit_mode");
config.sizeMode = comboSizeModes.options[comboSizeModes.selectedIndex].value;
config.modal = document.getElementById("shows_modal").checked;
config.draggable = document.getElementById("is_draggable").checked;
const comboTools = document.getElementById("inking_tool");
const inkColor = document.getElementById("rendering_color_box").value;
const comboBackgroundMode = document.getElementById("background_image_mode");
config.background = {color:document.getElementById("background_color_box").value,
alpha:document.getElementById("background_opacity").value*0.01,
mode:comboBackgroundMode.options[comboBackgroundMode.selectedIndex].value};
if ((document.getElementById("put_background_image").checked) && (backgroundImage)) {
config.background.image = backgroundImage;
}
if (document.getElementById("enable_timeout").checked) {
config.timeOut = {enabled:true};
config.timeOut.time = parseInt(document.getElementById("timeOutValue").value);
config.timeOut.onTimeOut = timeOutCallback;
}
config.minTimeOnSurface = parseInt(document.getElementById("minTimeOnSurface").value);
if (!document.getElementById("allowOutSide").checked) {
const self = this;
config.onOutSide = function() {
alert("OutSide stroke is not allowed. Please sign again");
self.clear();
return true; // for stop capturing
}
}
config.allowZeroPressure = document.getElementById("allowZeroPressure").checked;
return config;
}
As does the function captureFromCanvas
:
- Version 1
- Version 2
function captureFromCanvas() {
stuCapDialog = null;
const config = generateConfig();
config.source = {mouse:document.getElementById("allow_mouse_check").checked,
touch:document.getElementById("allow_touch_check").checked,
pen:document.getElementById("allow_pen_check").checked}
sigCaptDialog = new SigCaptDialog(config);
sigCaptDialog.addEventListener("ok", function() {
encryptSignature();
renderSignature();
});
sigCaptDialog.open(mSigObj, document.getElementById("who").value, document.getElementById("why").value, generateExtraData(), Module.KeyType.SHA512, documentHash);
sigCaptDialog.startCapture();
}
function captureFromCanvas() {
stuCapDialog = null;
const config = generateConfig();
config.source = {mouse:document.getElementById("allow_mouse_check").checked,
touch:document.getElementById("allow_touch_check").checked,
pen:document.getElementById("allow_pen_check").checked}
sigCaptDialog = new SigCaptDialog(config);
sigCaptDialog.addEventListener("ok", function() {
encryptSignature();
renderSignature();
});
//in this demo we use https://github.com/keithws/browser-report library for getting
//information about the os.
const webBrowserData = browserReportSync();
const osInfo = webBrowserData.os.name + " " + webBrowserData.os.version;
const digitizerInfo = webBrowserData.browser.name + " " + webBrowserData.browser.version;
const nicInfo = "";
const where = "";
sigCaptDialog.open(mSigObj, document.getElementById("who").value, document.getElementById("why").value, where, generateExtraData(), Module.KeyType.SHA512, documentHash, osInfo, digitizerInfo, nicInfo);
sigCaptDialog.startCapture();
}
The function captureFromSTU
needs to be made asynchronous and given the following additional adjustments.
- Version 1
- Version 2
function captureFromSTU() {
sigCaptDialog = null;
const config = generateConfig();
config.encryption = {
sessionId: window.crypto.getRandomValues(new Uint32Array(1))[0], // 32 bits random value
encryptionHandler: new MyEncryptionHandler(), // only necessary if connecting to STU-300/500/520
encryptionHandler2: new MyEncryptionHandler2(), // only necessary if connection to STU-430/530/540
};
stuCapDialog = new StuCaptDialog(config);
stuCapDialog.addEventListener("ok", function() {
encryptSignature();
renderSignature();
});
stuCapDialog.open(mSigObj, document.getElementById("who").value, document.getElementById("why").value, generateExtraData(), Module.KeyType.SHA512, documentHash);
}
async function captureFromSTU() {
sigCaptDialog = null;
const config = generateConfig();
config.encryption = {
sessionId: window.crypto.getRandomValues(new Uint32Array(1))[0], // 32 bits random value
encryptionHandler: new MyEncryptionHandler(), // only necessary if connecting to STU-300/500/520
encryptionHandler2: new MyEncryptionHandler2(), // only necessary if connection to STU-430/530/540
};
const stuDeviceStr = localStorage.getItem("stuDevice");
let stuDevice;
if (!stuDeviceStr) {
const devices = await com.WacomGSS.STU.UsbDevice.requestDevices();
if (devices.length > 0) {
stuDevice = devices[0];
localStorage.setItem("stuDevice", JSON.stringify({"vendorId":stuDevice.vendorId,
"productName":stuDevice.productName,
"productId":stuDevice.productId}));
setDeviceName();
} else {
throw "No STU devices found";
}
} else {
stuDevice = JSON.parse(stuDeviceStr);
// get all the devices that we have permissions to connect
await navigator.hid.getDevices().then(devices => {
devices.forEach(device => {
if (stuDevice.vendorId === device.vendorId && stuDevice.productId === device.productId && stuDevice.productName === device.productName) {
stuDevice = device;
}
});
});
}
config.stuDevice = stuDevice;
stuCapDialog = new StuCaptDialog(config);
stuCapDialog.addEventListener("ok", function() {
encryptSignature();
renderSignature();
});
//in this demo we use https://github.com/keithws/browser-report library for getting
//information about the os.
const webBrowserData = browserReportSync();
const osInfo = webBrowserData.os.name + " " + webBrowserData.os.version;
const nicInfo = "";
const where = "";
stuCapDialog.open(mSigObj, document.getElementById("who").value, document.getElementById("why").value, where, generateExtraData(), Module.KeyType.SHA512, documentHash, osInfo, nicInfo);
}
After this, add the following two functions: setDeviceName
and removeDevice
.
function setDeviceName() {
const stuDeviceStr = localStorage.getItem("stuDevice");
if (stuDeviceStr) {
document.getElementById("selectedStuDevice").innerHTML = JSON.parse(stuDeviceStr).productName;
} else {
document.getElementById("selectedStuDevice").innerHTML = "None";
}
}
function removeDevice() {
localStorage.removeItem("stuDevice");
setDeviceName();
}
Adjust the final several lines within renderSignatureImage
.
- Version 1
- Version 2
...
const inkColor = document.getElementById("rendering_color_box").value;
const comboTools = document.getElementById("inking_tool");
const inkTool = document.getElementById("use_will").checked ? tools[comboTools.options[comboTools.selectedIndex].value] : parseInt(document.getElementById("ink_width").value);
const image = await mSigObj.renderBitmap(renderWidth, renderHeight, "image/png", inkTool, inkColor, backgroundColor, 0, 0, renderFlags);
return image;
}
...
const inkColor = document.getElementById("rendering_color_box").value;
const inkWidth = parseInt(document.getElementById("ink_width").value);
const image = await mSigObj.renderBitmap(renderWidth, renderHeight, "image/png", inkWidth, inkColor, backgroundColor, 0, 0, renderFlags);
return image;
}
Adjust the function decodePKCS12
like so:
- Version 1
- Version 2
function decodePKCS12(file, password) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = evt => {
try {
const binary = evt && evt.target ? evt.target.result : null
if (!binary) {
reject(new Error('No file data'))
}
const p12Asn1 = forge.asn1.fromDer(binary)
const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, password)
const bags = p12.getBags({bagType: forge.pki.oids.certBag})
const cert = bags[forge.pki.oids.certBag][0];
if (cert?.cert?.validity?.notAfter < new Date()) {
reject("Certificate has expired");
}
const pkeyBags = p12.getBags({bagType: forge.pki.oids.pkcs8ShroudedKeyBag})
const keybag = pkeyBags[forge.pki.oids.pkcs8ShroudedKeyBag][0];
const privateKey = forge.pki.privateKeyToPem(keybag.key)
const publicKey = forge.pki.publicKeyToPem(forge.pki.setRsaPublicKey(keybag.key.n, keybag.key.e));
resolve({publicKey, privateKey})
} catch (e) {
reject(e)
}
}
reader.onerror = reject
reader.readAsBinaryString(file)
})
}
function decodePKCS12(file, password) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = evt => {
try {
const binary = evt && evt.target ? evt.target.result : null
if (!binary) {
reject(new Error('No file data'))
}
const p12Asn1 = forge.asn1.fromDer(binary)
const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, password)
const bags = p12.getBags({bagType: forge.pki.oids.certBag})
const cert = bags[forge.pki.oids.certBag][0];
//if (cert?.cert?.validity?.notAfter < new Date()) { //not supported by some browsers
if (cert && cert.validity && cert.validity.notAfter && cert.validity.notAfter < new Date()) {
reject("Certificate has expired");
}
const pkeyBags = p12.getBags({bagType: forge.pki.oids.pkcs8ShroudedKeyBag})
const keybag = pkeyBags[forge.pki.oids.pkcs8ShroudedKeyBag][0];
const privateKey = forge.pki.privateKeyToPem(keybag.key)
const publicKey = forge.pki.publicKeyToPem(forge.pki.setRsaPublicKey(keybag.key.n, keybag.key.e));
resolve({publicKey, privateKey})
} catch (e) {
reject(e)
}
}
reader.onerror = reject
reader.readAsBinaryString(file)
})
}
The function useWillCheck
should be removed.
function useWillCheck() {
document.getElementById("inking_tool").disabled = !document.getElementById("use_will").checked;
document.getElementById("ink_width").disabled = document.getElementById("use_will").checked;
}
The remaining adjustments for the HTML are:
- Adding a new div tag at the top of
<body>
:
- Version 1
- Version 2
<body>
<div class="wrapper">
<body>
<div id="initializeBanground" class="active" style="width:100%;height:100%;position:fixed;background:#cccccccc;">
<div style="position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);">
<table><tr><td><div class="loader"></div></td><td>Initializing, this could take a few seconds...</td></tr></table>
</div>
</div>
<div class="wrapper">
The next adjustment required is for capturing data from an STU:
- Version 1
- Version 2
<label for="document">Document:</label><br>
<input type="file" id="document" name="document" onchange="addDocumentHash()" disabled="disabled"><br><br>
<button id="capture_stu_btn" onClick="capture('STU')" disabled="disabled">Capture signature from STU tablet</button><br><br>
<p>
The input data for the signature can be taken from different sources:
<fieldset style="width:400px;height:40px;padding:5px;margin:5px">
<legend>Input sources</legend>
<input type="checkbox" name="allow_mouse_check" id="allow_mouse_check" checked="checked">
<label for="allow_mouse_check">Allow mouse</label>
<input type="checkbox" name="allow_touch_check" id="allow_touch_check" checked="checked">
<label for="allow_touch_check">Allow touch</label>
<input type="checkbox" name="allow_pen_check" id="allow_pen_check" checked="checked">
<label for="allow_pen_check">Allow pen</label>
</fieldset>
</p>
<button id="capture_canvas_btn" onClick="capture('Canvas')">Capture signature from Generic device</button>
<br><br>
<fieldset style="width:0;padding:5px;margin:5px;">
<legend>Signature</legend>
<div id="captureDiv" style="width:400px;height:330px;"></div>
<img id="signatureImage" style="display:none">
</fieldset>
<label for="document">Document:</label><br>
<input type="file" id="document" name="document" onchange="addDocumentHash()" disabled="disabled"><br><br>
<p>
Selected STU device: <span id="selectedStuDevice"></span>-<a name="removeDevice" href="#removeDevice" onClick="removeDevice()">Remove</a><br>
<button id="capture_stu_btn" onClick="capture('STU')" disabled="disabled">Capture signature from STU tablet</button><br><br>
</p>
<p>
The input data for the signature can be taken from different sources:
<fieldset style="width:400px;height:40px;padding:5px;margin:5px">
<legend>Input sources</legend>
<input type="checkbox" name="allow_mouse_check" id="allow_mouse_check" checked="checked">
<label for="allow_mouse_check">Allow mouse</label>
<input type="checkbox" name="allow_touch_check" id="allow_touch_check" checked="checked">
<label for="allow_touch_check">Allow touch</label>
<input type="checkbox" name="allow_pen_check" id="allow_pen_check" checked="checked">
<label for="allow_pen_check">Allow pen</label>
</fieldset>
</p>
<button id="capture_canvas_btn" onClick="capture('Canvas')" disabled="disabled">Capture signature from Generic device</button>
<br><br>
<p>Signature:</p>
<fieldset style="width:0;padding:0;margin:0;">
<div id="captureDiv" style="width:400px;height:330px;"></div>
<img id="signatureImage" style="display:none">
</fieldset>
The final adjustment needed is within the Settings section.
- Version 1
- Version 2
<div id="settings_div" class="tabcontent">
<h2>Settings</h2>
<div>
<fieldset style="width:400px;padding:5px;margin:5px">
<legend>Ink</legend>
<input type="checkbox" name="use_will" id="use_will" checked="checked" onchange="useWillCheck()">
<label for="use_will">use WILL</label>
<br><br>
<label for="ink_width">Ink width:</label>
<input type="input" name="ink_width" id="ink_width" value="2" disabled="disabled">
<br><br>
<label for="inking_tool">Inking tool:</label>
<select name="inking_tool" id="inking_tool">
<option value="pen">pen</option>
<option value="felt">felt</option>
<option value="brush">brush</option>
<option value="marker">marker</option>
<option value="pencil">pencil</option>
<option value="waterBrush">waterBrush</option>
<option value="inkBrush">inkBrush</option>
<option value="rainbowBrush">rainbowBrush</option>
<option value="crayon">crayon</option>
</select>
</br></br>
<label for="rendering_color_box">Ink color:</label>
<input type="color" name="rendering_color_box" id="rendering_color_box" value="#000F55">
<br>
<label for="background_color_box">Background color</label>
<input type="color" name="background_color_box" id="background_color_box" value="#ffffff">
<br>
<input type="checkbox" name="put_background_image" id="put_background_image">
<label for="background_image">Use background image</label><br>
<input type="file" id="background_image" name="background_image" onChange="loadBackgroundImage()" accept="image/*">
<br>
<label for="background_image_mode">Background image mode</label><br>
<select name="background_image_mode" id="background_image_mode">
<option value="none">None</option>
<option value="fit" selected="selected">Fit</option>
<option value="center">Center</option>
<option value="pattern">Pattern</option>
</select>
<br>
<label for="background_opacity">Background opacity</label>
<input type="range" min="1" max="100" value="100" id="background_opacity">
</fieldset>
</div>
<div id="settings_div" class="tabcontent">
<h2>Settings</h2>
<div>
<fieldset style="width:400px;padding:5px;margin:5px">
<legend>Ink</legend>
<label for="ink_width">Ink width:</label>
<input type="number" name="ink_width" id="ink_width" value="6">
</br></br>
<label for="rendering_color_box">Ink color:</label>
<input type="color" name="rendering_color_box" id="rendering_color_box" value="#0202FE">
<br>
<label for="background_color_box">Background color</label>
<input type="color" name="background_color_box" id="background_color_box" value="#ffffff">
<br>
<input type="checkbox" name="put_background_image" id="put_background_image">
<label for="background_image">Use background image</label><br>
<input type="file" id="background_image" name="background_image" onChange="loadBackgroundImage()" accept="image/*">
<br>
<label for="background_image_mode">Background image mode</label><br>
<select name="background_image_mode" id="background_image_mode">
<option value="none">None</option>
<option value="fit" selected="selected">Fit</option>
<option value="center">Center</option>
<option value="pattern">Pattern</option>
</select>
<br>
<label for="background_opacity">Background opacity</label>
<input type="range" min="1" max="100" value="100" id="background_opacity">
<br>
<input type="checkbox" name="allowOutSide" id="allowOutSide" checked="checked">
<label for="allowOutSide">Allow outside inking</label><br>
<input type="checkbox" name="allowZeroPressure" id="allowZeroPressure" checked="checked">
<label for="allowZeroPressure">Allow zero pressure</label><br>
</fieldset>
</div>