@tbsoft-gmbh/signature-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -0
- package/dist/assets-embedded.d.ts +12 -0
- package/dist/assets-embedded.js +37 -0
- package/dist/assets-embedded.js.map +1 -0
- package/dist/driver-hid.d.ts +45 -0
- package/dist/driver-hid.js +3777 -0
- package/dist/driver-hid.js.map +1 -0
- package/dist/font-8x13.d.ts +3 -0
- package/dist/font-8x13.js +145 -0
- package/dist/font-8x13.js.map +1 -0
- package/dist/hid-crypto.d.ts +58 -0
- package/dist/hid-crypto.js +138 -0
- package/dist/hid-crypto.js.map +1 -0
- package/dist/hid-display.d.ts +78 -0
- package/dist/hid-display.js +531 -0
- package/dist/hid-display.js.map +1 -0
- package/dist/hid-protocol.d.ts +227 -0
- package/dist/hid-protocol.js +2540 -0
- package/dist/hid-protocol.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +3900 -0
- package/dist/index.js.map +1 -0
- package/dist/png-decode.d.ts +14 -0
- package/dist/png-decode.js +141 -0
- package/dist/png-decode.js.map +1 -0
- package/dist/signature-renderer.d.ts +34 -0
- package/dist/signature-renderer.js +176 -0
- package/dist/signature-renderer.js.map +1 -0
- package/dist/types.d.ts +226 -0
- package/dist/types.js +46 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
- package/udev/99-signotec.rules +10 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal PNG decoder using only Node.js built-in zlib.
|
|
3
|
+
* Supports 8-bit RGB, RGBA, Grayscale, and Grayscale+Alpha PNGs.
|
|
4
|
+
* No external dependencies.
|
|
5
|
+
*/
|
|
6
|
+
interface DecodedPng {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
channels: number;
|
|
10
|
+
data: Buffer;
|
|
11
|
+
}
|
|
12
|
+
declare function decodePng(buf: Buffer): DecodedPng | null;
|
|
13
|
+
|
|
14
|
+
export { type DecodedPng, decodePng };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/png-decode.ts
|
|
31
|
+
var png_decode_exports = {};
|
|
32
|
+
__export(png_decode_exports, {
|
|
33
|
+
decodePng: () => decodePng
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(png_decode_exports);
|
|
36
|
+
var import_zlib = __toESM(require("zlib"));
|
|
37
|
+
function decodePng(buf) {
|
|
38
|
+
if (buf[0] !== 137 || buf[1] !== 80 || buf[2] !== 78 || buf[3] !== 71) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
let offset = 8;
|
|
42
|
+
let width = 0, height = 0, bitDepth = 0, colorType = 0;
|
|
43
|
+
const idatChunks = [];
|
|
44
|
+
while (offset < buf.length) {
|
|
45
|
+
const chunkLen = buf.readUInt32BE(offset);
|
|
46
|
+
const chunkType = buf.toString("ascii", offset + 4, offset + 8);
|
|
47
|
+
if (chunkType === "IHDR") {
|
|
48
|
+
width = buf.readUInt32BE(offset + 8);
|
|
49
|
+
height = buf.readUInt32BE(offset + 12);
|
|
50
|
+
bitDepth = buf[offset + 16];
|
|
51
|
+
colorType = buf[offset + 17];
|
|
52
|
+
} else if (chunkType === "IDAT") {
|
|
53
|
+
idatChunks.push(buf.slice(offset + 8, offset + 8 + chunkLen));
|
|
54
|
+
} else if (chunkType === "IEND") {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
offset += 12 + chunkLen;
|
|
58
|
+
}
|
|
59
|
+
if (width === 0 || height === 0 || idatChunks.length === 0) return null;
|
|
60
|
+
let channels;
|
|
61
|
+
switch (colorType) {
|
|
62
|
+
case 0:
|
|
63
|
+
channels = 1;
|
|
64
|
+
break;
|
|
65
|
+
// Grayscale
|
|
66
|
+
case 2:
|
|
67
|
+
channels = 3;
|
|
68
|
+
break;
|
|
69
|
+
// RGB
|
|
70
|
+
case 4:
|
|
71
|
+
channels = 2;
|
|
72
|
+
break;
|
|
73
|
+
// Grayscale + Alpha
|
|
74
|
+
case 6:
|
|
75
|
+
channels = 4;
|
|
76
|
+
break;
|
|
77
|
+
// RGBA
|
|
78
|
+
default:
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const compressed = Buffer.concat(idatChunks);
|
|
82
|
+
let decompressed;
|
|
83
|
+
try {
|
|
84
|
+
decompressed = import_zlib.default.inflateSync(compressed);
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const bytesPerPixel = channels * (bitDepth / 8);
|
|
89
|
+
const stride = width * bytesPerPixel;
|
|
90
|
+
const pixels = Buffer.alloc(height * stride);
|
|
91
|
+
let srcOffset = 0;
|
|
92
|
+
for (let y = 0; y < height; y++) {
|
|
93
|
+
const filterType = decompressed[srcOffset++];
|
|
94
|
+
const rowStart = y * stride;
|
|
95
|
+
const prevRowStart = (y - 1) * stride;
|
|
96
|
+
for (let x = 0; x < stride; x++) {
|
|
97
|
+
const raw = decompressed[srcOffset++];
|
|
98
|
+
let value;
|
|
99
|
+
switch (filterType) {
|
|
100
|
+
case 0:
|
|
101
|
+
value = raw;
|
|
102
|
+
break;
|
|
103
|
+
case 1:
|
|
104
|
+
value = raw + (x >= bytesPerPixel ? pixels[rowStart + x - bytesPerPixel] : 0);
|
|
105
|
+
break;
|
|
106
|
+
case 2:
|
|
107
|
+
value = raw + (y > 0 ? pixels[prevRowStart + x] : 0);
|
|
108
|
+
break;
|
|
109
|
+
case 3:
|
|
110
|
+
const left = x >= bytesPerPixel ? pixels[rowStart + x - bytesPerPixel] : 0;
|
|
111
|
+
const up = y > 0 ? pixels[prevRowStart + x] : 0;
|
|
112
|
+
value = raw + Math.floor((left + up) / 2);
|
|
113
|
+
break;
|
|
114
|
+
case 4:
|
|
115
|
+
const a = x >= bytesPerPixel ? pixels[rowStart + x - bytesPerPixel] : 0;
|
|
116
|
+
const b = y > 0 ? pixels[prevRowStart + x] : 0;
|
|
117
|
+
const c = x >= bytesPerPixel && y > 0 ? pixels[prevRowStart + x - bytesPerPixel] : 0;
|
|
118
|
+
value = raw + paethPredictor(a, b, c);
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
value = raw;
|
|
122
|
+
}
|
|
123
|
+
pixels[rowStart + x] = value & 255;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { width, height, channels, data: pixels };
|
|
127
|
+
}
|
|
128
|
+
function paethPredictor(a, b, c) {
|
|
129
|
+
const p = a + b - c;
|
|
130
|
+
const pa = Math.abs(p - a);
|
|
131
|
+
const pb = Math.abs(p - b);
|
|
132
|
+
const pc = Math.abs(p - c);
|
|
133
|
+
if (pa <= pb && pa <= pc) return a;
|
|
134
|
+
if (pb <= pc) return b;
|
|
135
|
+
return c;
|
|
136
|
+
}
|
|
137
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
138
|
+
0 && (module.exports = {
|
|
139
|
+
decodePng
|
|
140
|
+
});
|
|
141
|
+
//# sourceMappingURL=png-decode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/png-decode.ts"],"sourcesContent":["/**\r\n * Minimal PNG decoder using only Node.js built-in zlib.\r\n * Supports 8-bit RGB, RGBA, Grayscale, and Grayscale+Alpha PNGs.\r\n * No external dependencies.\r\n */\r\n\r\nimport zlib from \"zlib\";\r\n\r\nexport interface DecodedPng {\r\n width: number;\r\n height: number;\r\n channels: number; // 1=gray, 2=gray+alpha, 3=RGB, 4=RGBA\r\n data: Buffer; // Raw pixel data, row-major, channels interleaved\r\n}\r\n\r\nexport function decodePng(buf: Buffer): DecodedPng | null {\r\n // Verify PNG signature\r\n if (buf[0] !== 0x89 || buf[1] !== 0x50 || buf[2] !== 0x4E || buf[3] !== 0x47) {\r\n return null;\r\n }\r\n\r\n let offset = 8; // Skip signature\r\n let width = 0, height = 0, bitDepth = 0, colorType = 0;\r\n const idatChunks: Buffer[] = [];\r\n\r\n // Parse chunks\r\n while (offset < buf.length) {\r\n const chunkLen = buf.readUInt32BE(offset);\r\n const chunkType = buf.toString(\"ascii\", offset + 4, offset + 8);\r\n\r\n if (chunkType === \"IHDR\") {\r\n width = buf.readUInt32BE(offset + 8);\r\n height = buf.readUInt32BE(offset + 12);\r\n bitDepth = buf[offset + 16];\r\n colorType = buf[offset + 17];\r\n } else if (chunkType === \"IDAT\") {\r\n idatChunks.push(buf.slice(offset + 8, offset + 8 + chunkLen));\r\n } else if (chunkType === \"IEND\") {\r\n break;\r\n }\r\n\r\n offset += 12 + chunkLen; // 4 len + 4 type + data + 4 crc\r\n }\r\n\r\n if (width === 0 || height === 0 || idatChunks.length === 0) return null;\r\n\r\n // Determine channels from color type\r\n let channels: number;\r\n switch (colorType) {\r\n case 0: channels = 1; break; // Grayscale\r\n case 2: channels = 3; break; // RGB\r\n case 4: channels = 2; break; // Grayscale + Alpha\r\n case 6: channels = 4; break; // RGBA\r\n default: return null; // Indexed/other not supported\r\n }\r\n\r\n // Decompress IDAT data\r\n const compressed = Buffer.concat(idatChunks);\r\n let decompressed: Buffer;\r\n try {\r\n decompressed = zlib.inflateSync(compressed);\r\n } catch {\r\n return null;\r\n }\r\n\r\n // Apply PNG filtering (each row has a filter byte prefix)\r\n const bytesPerPixel = channels * (bitDepth / 8);\r\n const stride = width * bytesPerPixel;\r\n const pixels = Buffer.alloc(height * stride);\r\n\r\n let srcOffset = 0;\r\n for (let y = 0; y < height; y++) {\r\n const filterType = decompressed[srcOffset++];\r\n const rowStart = y * stride;\r\n const prevRowStart = (y - 1) * stride;\r\n\r\n for (let x = 0; x < stride; x++) {\r\n const raw = decompressed[srcOffset++];\r\n let value: number;\r\n\r\n switch (filterType) {\r\n case 0: // None\r\n value = raw;\r\n break;\r\n case 1: // Sub\r\n value = raw + (x >= bytesPerPixel ? pixels[rowStart + x - bytesPerPixel] : 0);\r\n break;\r\n case 2: // Up\r\n value = raw + (y > 0 ? pixels[prevRowStart + x] : 0);\r\n break;\r\n case 3: // Average\r\n const left = x >= bytesPerPixel ? pixels[rowStart + x - bytesPerPixel] : 0;\r\n const up = y > 0 ? pixels[prevRowStart + x] : 0;\r\n value = raw + Math.floor((left + up) / 2);\r\n break;\r\n case 4: // Paeth\r\n const a = x >= bytesPerPixel ? pixels[rowStart + x - bytesPerPixel] : 0;\r\n const b = y > 0 ? pixels[prevRowStart + x] : 0;\r\n const c = (x >= bytesPerPixel && y > 0) ? pixels[prevRowStart + x - bytesPerPixel] : 0;\r\n value = raw + paethPredictor(a, b, c);\r\n break;\r\n default:\r\n value = raw;\r\n }\r\n\r\n pixels[rowStart + x] = value & 0xFF;\r\n }\r\n }\r\n\r\n return { width, height, channels, data: pixels };\r\n}\r\n\r\nfunction paethPredictor(a: number, b: number, c: number): number {\r\n const p = a + b - c;\r\n const pa = Math.abs(p - a);\r\n const pb = Math.abs(p - b);\r\n const pc = Math.abs(p - c);\r\n if (pa <= pb && pa <= pc) return a;\r\n if (pb <= pc) return b;\r\n return c;\r\n}\r\n"],"mappings":"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","names":["zlib"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders signature strokes into a PNG image buffer.
|
|
3
|
+
* Pure TypeScript implementation - no canvas or native dependencies.
|
|
4
|
+
* Uses zlib for PNG compression (built into Node.js).
|
|
5
|
+
*/
|
|
6
|
+
type Point = {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
pressure?: number;
|
|
10
|
+
};
|
|
11
|
+
type Stroke = Point[];
|
|
12
|
+
interface RenderOptions {
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
strokeWidth: number;
|
|
16
|
+
strokeColor: {
|
|
17
|
+
r: number;
|
|
18
|
+
g: number;
|
|
19
|
+
b: number;
|
|
20
|
+
};
|
|
21
|
+
backgroundColor: {
|
|
22
|
+
r: number;
|
|
23
|
+
g: number;
|
|
24
|
+
b: number;
|
|
25
|
+
};
|
|
26
|
+
padding: number;
|
|
27
|
+
smooth: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Render signature strokes to a PNG buffer.
|
|
31
|
+
*/
|
|
32
|
+
declare function renderSignaturePng(strokes: Stroke[], sensorWidth: number, sensorHeight: number, options?: Partial<RenderOptions>): Buffer;
|
|
33
|
+
|
|
34
|
+
export { type RenderOptions, renderSignaturePng };
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/signature-renderer.ts
|
|
31
|
+
var signature_renderer_exports = {};
|
|
32
|
+
__export(signature_renderer_exports, {
|
|
33
|
+
renderSignaturePng: () => renderSignaturePng
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(signature_renderer_exports);
|
|
36
|
+
var import_zlib = __toESM(require("zlib"));
|
|
37
|
+
var DEFAULT_OPTIONS = {
|
|
38
|
+
width: 400,
|
|
39
|
+
height: 200,
|
|
40
|
+
strokeWidth: 2,
|
|
41
|
+
strokeColor: { r: 0, g: 0, b: 0 },
|
|
42
|
+
backgroundColor: { r: 255, g: 255, b: 255 },
|
|
43
|
+
padding: 10,
|
|
44
|
+
smooth: true
|
|
45
|
+
};
|
|
46
|
+
function renderSignaturePng(strokes, sensorWidth, sensorHeight, options = {}) {
|
|
47
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
48
|
+
const { width, height, strokeWidth, strokeColor, backgroundColor, padding } = opts;
|
|
49
|
+
const pixels = Buffer.alloc(width * height * 4);
|
|
50
|
+
for (let i = 0; i < width * height; i++) {
|
|
51
|
+
pixels[i * 4] = backgroundColor.r;
|
|
52
|
+
pixels[i * 4 + 1] = backgroundColor.g;
|
|
53
|
+
pixels[i * 4 + 2] = backgroundColor.b;
|
|
54
|
+
pixels[i * 4 + 3] = 255;
|
|
55
|
+
}
|
|
56
|
+
if (strokes.length === 0) {
|
|
57
|
+
return encodePng(pixels, width, height);
|
|
58
|
+
}
|
|
59
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
60
|
+
for (const stroke of strokes) {
|
|
61
|
+
for (const pt of stroke) {
|
|
62
|
+
if (pt.x < minX) minX = pt.x;
|
|
63
|
+
if (pt.y < minY) minY = pt.y;
|
|
64
|
+
if (pt.x > maxX) maxX = pt.x;
|
|
65
|
+
if (pt.y > maxY) maxY = pt.y;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const dataWidth = maxX - minX || 1;
|
|
69
|
+
const dataHeight = maxY - minY || 1;
|
|
70
|
+
const scaleX = (width - padding * 2) / dataWidth;
|
|
71
|
+
const scaleY = (height - padding * 2) / dataHeight;
|
|
72
|
+
const scale = Math.min(scaleX, scaleY);
|
|
73
|
+
const offsetX = padding + (width - padding * 2 - dataWidth * scale) / 2;
|
|
74
|
+
const offsetY = padding + (height - padding * 2 - dataHeight * scale) / 2;
|
|
75
|
+
for (const stroke of strokes) {
|
|
76
|
+
if (stroke.length < 2) continue;
|
|
77
|
+
for (let i = 1; i < stroke.length; i++) {
|
|
78
|
+
const x0 = offsetX + (stroke[i - 1].x - minX) * scale;
|
|
79
|
+
const y0 = offsetY + (stroke[i - 1].y - minY) * scale;
|
|
80
|
+
const x1 = offsetX + (stroke[i].x - minX) * scale;
|
|
81
|
+
const y1 = offsetY + (stroke[i].y - minY) * scale;
|
|
82
|
+
drawLine(pixels, width, height, x0, y0, x1, y1, strokeWidth, strokeColor);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return encodePng(pixels, width, height);
|
|
86
|
+
}
|
|
87
|
+
function drawLine(pixels, imgWidth, imgHeight, x0, y0, x1, y1, thickness, color) {
|
|
88
|
+
const dx = Math.abs(x1 - x0);
|
|
89
|
+
const dy = Math.abs(y1 - y0);
|
|
90
|
+
const sx = x0 < x1 ? 1 : -1;
|
|
91
|
+
const sy = y0 < y1 ? 1 : -1;
|
|
92
|
+
let err = dx - dy;
|
|
93
|
+
const steps = Math.max(Math.ceil(Math.sqrt(dx * dx + dy * dy)), 1);
|
|
94
|
+
const radius = thickness / 2;
|
|
95
|
+
for (let step = 0; step <= steps; step++) {
|
|
96
|
+
const t = steps > 0 ? step / steps : 0;
|
|
97
|
+
const cx = x0 + (x1 - x0) * t;
|
|
98
|
+
const cy = y0 + (y1 - y0) * t;
|
|
99
|
+
const r = Math.ceil(radius);
|
|
100
|
+
for (let dy2 = -r; dy2 <= r; dy2++) {
|
|
101
|
+
for (let dx2 = -r; dx2 <= r; dx2++) {
|
|
102
|
+
if (dx2 * dx2 + dy2 * dy2 <= radius * radius) {
|
|
103
|
+
const px = Math.round(cx + dx2);
|
|
104
|
+
const py = Math.round(cy + dy2);
|
|
105
|
+
if (px >= 0 && px < imgWidth && py >= 0 && py < imgHeight) {
|
|
106
|
+
const idx = (py * imgWidth + px) * 4;
|
|
107
|
+
pixels[idx] = color.r;
|
|
108
|
+
pixels[idx + 1] = color.g;
|
|
109
|
+
pixels[idx + 2] = color.b;
|
|
110
|
+
pixels[idx + 3] = 255;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function encodePng(pixels, width, height) {
|
|
118
|
+
const rawData = Buffer.alloc(height * (1 + width * 4));
|
|
119
|
+
for (let y = 0; y < height; y++) {
|
|
120
|
+
rawData[y * (1 + width * 4)] = 0;
|
|
121
|
+
pixels.copy(
|
|
122
|
+
rawData,
|
|
123
|
+
y * (1 + width * 4) + 1,
|
|
124
|
+
y * width * 4,
|
|
125
|
+
(y + 1) * width * 4
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const compressed = import_zlib.default.deflateSync(rawData);
|
|
129
|
+
const chunks = [];
|
|
130
|
+
chunks.push(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));
|
|
131
|
+
const ihdr = Buffer.alloc(13);
|
|
132
|
+
ihdr.writeUInt32BE(width, 0);
|
|
133
|
+
ihdr.writeUInt32BE(height, 4);
|
|
134
|
+
ihdr[8] = 8;
|
|
135
|
+
ihdr[9] = 6;
|
|
136
|
+
ihdr[10] = 0;
|
|
137
|
+
ihdr[11] = 0;
|
|
138
|
+
ihdr[12] = 0;
|
|
139
|
+
chunks.push(pngChunk("IHDR", ihdr));
|
|
140
|
+
chunks.push(pngChunk("IDAT", compressed));
|
|
141
|
+
chunks.push(pngChunk("IEND", Buffer.alloc(0)));
|
|
142
|
+
return Buffer.concat(chunks);
|
|
143
|
+
}
|
|
144
|
+
function pngChunk(type, data) {
|
|
145
|
+
const length = Buffer.alloc(4);
|
|
146
|
+
length.writeUInt32BE(data.length, 0);
|
|
147
|
+
const typeAndData = Buffer.concat([Buffer.from(type, "ascii"), data]);
|
|
148
|
+
const crc = crc32(typeAndData);
|
|
149
|
+
const crcBuf = Buffer.alloc(4);
|
|
150
|
+
crcBuf.writeUInt32BE(crc >>> 0, 0);
|
|
151
|
+
return Buffer.concat([length, typeAndData, crcBuf]);
|
|
152
|
+
}
|
|
153
|
+
var CRC_TABLE = [];
|
|
154
|
+
for (let n = 0; n < 256; n++) {
|
|
155
|
+
let c = n;
|
|
156
|
+
for (let k = 0; k < 8; k++) {
|
|
157
|
+
if (c & 1) {
|
|
158
|
+
c = 3988292384 ^ c >>> 1;
|
|
159
|
+
} else {
|
|
160
|
+
c = c >>> 1;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
CRC_TABLE[n] = c;
|
|
164
|
+
}
|
|
165
|
+
function crc32(data) {
|
|
166
|
+
let crc = 4294967295;
|
|
167
|
+
for (let i = 0; i < data.length; i++) {
|
|
168
|
+
crc = CRC_TABLE[(crc ^ data[i]) & 255] ^ crc >>> 8;
|
|
169
|
+
}
|
|
170
|
+
return (crc ^ 4294967295) >>> 0;
|
|
171
|
+
}
|
|
172
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
173
|
+
0 && (module.exports = {
|
|
174
|
+
renderSignaturePng
|
|
175
|
+
});
|
|
176
|
+
//# sourceMappingURL=signature-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/signature-renderer.ts"],"sourcesContent":["/**\r\n * Renders signature strokes into a PNG image buffer.\r\n * Pure TypeScript implementation - no canvas or native dependencies.\r\n * Uses zlib for PNG compression (built into Node.js).\r\n */\r\n\r\nimport zlib from \"zlib\";\r\n\r\ntype Point = { x: number; y: number; pressure?: number };\r\ntype Stroke = Point[];\r\n\r\nexport interface RenderOptions {\r\n width: number;\r\n height: number;\r\n strokeWidth: number;\r\n strokeColor: { r: number; g: number; b: number };\r\n backgroundColor: { r: number; g: number; b: number };\r\n padding: number;\r\n smooth: boolean;\r\n}\r\n\r\nconst DEFAULT_OPTIONS: RenderOptions = {\r\n width: 400,\r\n height: 200,\r\n strokeWidth: 2,\r\n strokeColor: { r: 0, g: 0, b: 0 },\r\n backgroundColor: { r: 255, g: 255, b: 255 },\r\n padding: 10,\r\n smooth: true,\r\n};\r\n\r\n/**\r\n * Render signature strokes to a PNG buffer.\r\n */\r\nexport function renderSignaturePng(\r\n strokes: Stroke[],\r\n sensorWidth: number,\r\n sensorHeight: number,\r\n options: Partial<RenderOptions> = {}\r\n): Buffer {\r\n const opts = { ...DEFAULT_OPTIONS, ...options };\r\n const { width, height, strokeWidth, strokeColor, backgroundColor, padding } = opts;\r\n\r\n // Create RGBA pixel buffer\r\n const pixels = Buffer.alloc(width * height * 4);\r\n\r\n // Fill background\r\n for (let i = 0; i < width * height; i++) {\r\n pixels[i * 4] = backgroundColor.r;\r\n pixels[i * 4 + 1] = backgroundColor.g;\r\n pixels[i * 4 + 2] = backgroundColor.b;\r\n pixels[i * 4 + 3] = 255;\r\n }\r\n\r\n if (strokes.length === 0) {\r\n return encodePng(pixels, width, height);\r\n }\r\n\r\n // Calculate bounding box of all strokes\r\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\r\n for (const stroke of strokes) {\r\n for (const pt of stroke) {\r\n if (pt.x < minX) minX = pt.x;\r\n if (pt.y < minY) minY = pt.y;\r\n if (pt.x > maxX) maxX = pt.x;\r\n if (pt.y > maxY) maxY = pt.y;\r\n }\r\n }\r\n\r\n // Scale to fit output dimensions with padding\r\n const dataWidth = maxX - minX || 1;\r\n const dataHeight = maxY - minY || 1;\r\n const scaleX = (width - padding * 2) / dataWidth;\r\n const scaleY = (height - padding * 2) / dataHeight;\r\n const scale = Math.min(scaleX, scaleY);\r\n const offsetX = padding + (width - padding * 2 - dataWidth * scale) / 2;\r\n const offsetY = padding + (height - padding * 2 - dataHeight * scale) / 2;\r\n\r\n // Draw strokes\r\n for (const stroke of strokes) {\r\n if (stroke.length < 2) continue;\r\n\r\n for (let i = 1; i < stroke.length; i++) {\r\n const x0 = offsetX + (stroke[i - 1].x - minX) * scale;\r\n const y0 = offsetY + (stroke[i - 1].y - minY) * scale;\r\n const x1 = offsetX + (stroke[i].x - minX) * scale;\r\n const y1 = offsetY + (stroke[i].y - minY) * scale;\r\n\r\n drawLine(pixels, width, height, x0, y0, x1, y1, strokeWidth, strokeColor);\r\n }\r\n }\r\n\r\n return encodePng(pixels, width, height);\r\n}\r\n\r\n/**\r\n * Draw an anti-aliased line with thickness using Bresenham + circle brush.\r\n */\r\nfunction drawLine(\r\n pixels: Buffer,\r\n imgWidth: number,\r\n imgHeight: number,\r\n x0: number, y0: number,\r\n x1: number, y1: number,\r\n thickness: number,\r\n color: { r: number; g: number; b: number }\r\n): void {\r\n const dx = Math.abs(x1 - x0);\r\n const dy = Math.abs(y1 - y0);\r\n const sx = x0 < x1 ? 1 : -1;\r\n const sy = y0 < y1 ? 1 : -1;\r\n let err = dx - dy;\r\n\r\n const steps = Math.max(Math.ceil(Math.sqrt(dx * dx + dy * dy)), 1);\r\n const radius = thickness / 2;\r\n\r\n for (let step = 0; step <= steps; step++) {\r\n const t = steps > 0 ? step / steps : 0;\r\n const cx = x0 + (x1 - x0) * t;\r\n const cy = y0 + (y1 - y0) * t;\r\n\r\n // Draw filled circle at each step\r\n const r = Math.ceil(radius);\r\n for (let dy = -r; dy <= r; dy++) {\r\n for (let dx = -r; dx <= r; dx++) {\r\n if (dx * dx + dy * dy <= radius * radius) {\r\n const px = Math.round(cx + dx);\r\n const py = Math.round(cy + dy);\r\n if (px >= 0 && px < imgWidth && py >= 0 && py < imgHeight) {\r\n const idx = (py * imgWidth + px) * 4;\r\n pixels[idx] = color.r;\r\n pixels[idx + 1] = color.g;\r\n pixels[idx + 2] = color.b;\r\n pixels[idx + 3] = 255;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Encode RGBA pixel buffer as PNG.\r\n * Minimal PNG encoder - no external dependencies.\r\n */\r\nfunction encodePng(pixels: Buffer, width: number, height: number): Buffer {\r\n // Build raw image data with filter bytes\r\n const rawData = Buffer.alloc(height * (1 + width * 4));\r\n for (let y = 0; y < height; y++) {\r\n rawData[y * (1 + width * 4)] = 0; // Filter: None\r\n pixels.copy(\r\n rawData,\r\n y * (1 + width * 4) + 1,\r\n y * width * 4,\r\n (y + 1) * width * 4\r\n );\r\n }\r\n\r\n // Compress with zlib\r\n const compressed = zlib.deflateSync(rawData);\r\n\r\n // Build PNG file\r\n const chunks: Buffer[] = [];\r\n\r\n // PNG signature\r\n chunks.push(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));\r\n\r\n // IHDR chunk\r\n const ihdr = Buffer.alloc(13);\r\n ihdr.writeUInt32BE(width, 0);\r\n ihdr.writeUInt32BE(height, 4);\r\n ihdr[8] = 8; // bit depth\r\n ihdr[9] = 6; // color type: RGBA\r\n ihdr[10] = 0; // compression\r\n ihdr[11] = 0; // filter\r\n ihdr[12] = 0; // interlace\r\n chunks.push(pngChunk(\"IHDR\", ihdr));\r\n\r\n // IDAT chunk\r\n chunks.push(pngChunk(\"IDAT\", compressed));\r\n\r\n // IEND chunk\r\n chunks.push(pngChunk(\"IEND\", Buffer.alloc(0)));\r\n\r\n return Buffer.concat(chunks);\r\n}\r\n\r\nfunction pngChunk(type: string, data: Buffer): Buffer {\r\n const length = Buffer.alloc(4);\r\n length.writeUInt32BE(data.length, 0);\r\n\r\n const typeAndData = Buffer.concat([Buffer.from(type, \"ascii\"), data]);\r\n const crc = crc32(typeAndData);\r\n const crcBuf = Buffer.alloc(4);\r\n crcBuf.writeUInt32BE(crc >>> 0, 0);\r\n\r\n return Buffer.concat([length, typeAndData, crcBuf]);\r\n}\r\n\r\n// CRC-32 lookup table\r\nconst CRC_TABLE: number[] = [];\r\nfor (let n = 0; n < 256; n++) {\r\n let c = n;\r\n for (let k = 0; k < 8; k++) {\r\n if (c & 1) {\r\n c = 0xEDB88320 ^ (c >>> 1);\r\n } else {\r\n c = c >>> 1;\r\n }\r\n }\r\n CRC_TABLE[n] = c;\r\n}\r\n\r\nfunction crc32(data: Buffer): number {\r\n let crc = 0xFFFFFFFF;\r\n for (let i = 0; i < data.length; i++) {\r\n crc = CRC_TABLE[(crc ^ data[i]) & 0xFF] ^ (crc >>> 8);\r\n }\r\n return (crc ^ 0xFFFFFFFF) >>> 0;\r\n}\r\n"],"mappings":"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","names":["dy","dx","zlib"]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the Signotec Pad SDK.
|
|
3
|
+
* @module types
|
|
4
|
+
*/
|
|
5
|
+
/** Information about a connected Signotec signing pad. */
|
|
6
|
+
type DeviceInfo = {
|
|
7
|
+
/** Unique identifier (serial number or device path fallback). */
|
|
8
|
+
serialNo: string;
|
|
9
|
+
/** Device type code (see DEVICE_TYPE_MAPPINGS). */
|
|
10
|
+
type: number;
|
|
11
|
+
/** Human-readable device model name. */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Manufacturer name (always "Signotec"). */
|
|
14
|
+
vendor: string;
|
|
15
|
+
};
|
|
16
|
+
/** Map of device type codes to human-readable model names. */
|
|
17
|
+
declare const DEVICE_TYPE_MAPPINGS: Record<number, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Handler for user-initiated events (confirm/cancel) from the signing pad.
|
|
20
|
+
* @param event - "confirm" when signature accepted, "cancel" when cancelled
|
|
21
|
+
* @param data - Contains serialNo and base64 PNG image (on confirm)
|
|
22
|
+
*/
|
|
23
|
+
type SignatureEventHandler = {
|
|
24
|
+
(event: "cancel", data: {
|
|
25
|
+
serialNo: string;
|
|
26
|
+
}): void;
|
|
27
|
+
(event: "confirm", data: {
|
|
28
|
+
serialNo: string;
|
|
29
|
+
base64Img: string;
|
|
30
|
+
}): void;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Handler for real-time signature data streaming.
|
|
34
|
+
* @param event - "liveData" for each pen point, "clear" when signature cleared (retry)
|
|
35
|
+
* @param data - Contains point coordinates (x, y) and serialNo
|
|
36
|
+
*/
|
|
37
|
+
type SignatureEventHandlerLive = {
|
|
38
|
+
(event: "liveData", data: {
|
|
39
|
+
point: {
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
pressure?: number;
|
|
43
|
+
};
|
|
44
|
+
serialNo: string;
|
|
45
|
+
}): void;
|
|
46
|
+
(event: "clear", data: {
|
|
47
|
+
serialNo: string;
|
|
48
|
+
}): void;
|
|
49
|
+
};
|
|
50
|
+
/** Combined callback handlers for a signing session. */
|
|
51
|
+
type SignatureCallbackHandlers = {
|
|
52
|
+
/** Fires on user actions: confirm (with signature image) or cancel. */
|
|
53
|
+
onUserEvent: SignatureEventHandler;
|
|
54
|
+
/** Fires on pen movement (liveData) or signature clear (retry). */
|
|
55
|
+
onSignatureData: SignatureEventHandlerLive;
|
|
56
|
+
};
|
|
57
|
+
/** A single line of text displayed on the signing pad. */
|
|
58
|
+
type DisplayLine = {
|
|
59
|
+
/** Label prefix (e.g., "LFS:", "Kunde:"). */
|
|
60
|
+
label: string;
|
|
61
|
+
/** Content value displayed after the label. */
|
|
62
|
+
content: string | number;
|
|
63
|
+
/** Font scale factor (1 = tiny 5x7, 2 = normal, 3 = large). Default: 2 */
|
|
64
|
+
fontSize?: number;
|
|
65
|
+
};
|
|
66
|
+
/** Content displayed on the signing pad during a session. */
|
|
67
|
+
type SignatureDisplayData = {
|
|
68
|
+
/** Main content area (up to 4 lines, displayed below buttons). */
|
|
69
|
+
body?: {
|
|
70
|
+
line1?: DisplayLine | null;
|
|
71
|
+
line2?: DisplayLine | null;
|
|
72
|
+
line3?: DisplayLine | null;
|
|
73
|
+
line4?: DisplayLine | null;
|
|
74
|
+
} | null;
|
|
75
|
+
/** Footer area (up to 2 lines, displayed at bottom). */
|
|
76
|
+
footer?: {
|
|
77
|
+
line1?: DisplayLine | null;
|
|
78
|
+
line2?: DisplayLine | null;
|
|
79
|
+
} | null;
|
|
80
|
+
};
|
|
81
|
+
/** Options for the rendered signature image output. */
|
|
82
|
+
type SignatureOutputOptions = {
|
|
83
|
+
/** Pen stroke width in pixels. Default: 2 */
|
|
84
|
+
strokeWidth?: number;
|
|
85
|
+
/** Output image dimensions. Default: 400x200 */
|
|
86
|
+
imageSize?: {
|
|
87
|
+
width: number;
|
|
88
|
+
height: number;
|
|
89
|
+
};
|
|
90
|
+
/** DPI resolution for the output image. Default: 300 */
|
|
91
|
+
resolution?: number;
|
|
92
|
+
};
|
|
93
|
+
/** Options passed to startSigningProcess. */
|
|
94
|
+
type StartSignatureOptions = {
|
|
95
|
+
/** Text content to display on the pad during signing. */
|
|
96
|
+
displayData: SignatureDisplayData;
|
|
97
|
+
/** Configuration for the rendered signature image. */
|
|
98
|
+
outputOptions?: SignatureOutputOptions;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Configuration for the HID driver.
|
|
102
|
+
* Tune timeouts for slow USB-over-IP connections.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* // For USB-over-IP with high latency:
|
|
107
|
+
* const driver = createHidDriver({
|
|
108
|
+
* commandTimeout: 5000,
|
|
109
|
+
* chunkDelayMs: 10,
|
|
110
|
+
* maxRetries: 3,
|
|
111
|
+
* });
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
type DriverConfig = {
|
|
115
|
+
/** Timeout for simple HID commands (ms). Default: 3000 */
|
|
116
|
+
commandTimeout?: number;
|
|
117
|
+
/** Timeout for image transfer operations (ms). Default: 15000 */
|
|
118
|
+
imageTransferTimeout?: number;
|
|
119
|
+
/** Timeout for flash store operations (ms). Default: 25000 */
|
|
120
|
+
flashStoreTimeout?: number;
|
|
121
|
+
/** Delay between data chunks during image transfer (ms). Default: 2.
|
|
122
|
+
* Increase for slow USB-over-IP connections. */
|
|
123
|
+
chunkDelayMs?: number;
|
|
124
|
+
/** Max retry attempts for failed HID commands. Default: 2 */
|
|
125
|
+
maxRetries?: number;
|
|
126
|
+
/** Max reconnection attempts after device disconnect. Default: 10 */
|
|
127
|
+
reconnectAttempts?: number;
|
|
128
|
+
/** Delay between reconnection attempts (ms). Default: 2000 */
|
|
129
|
+
reconnectIntervalMs?: number;
|
|
130
|
+
/** Logger instance. Defaults to console. Set to null to suppress logs. */
|
|
131
|
+
logger?: Logger | null;
|
|
132
|
+
/**
|
|
133
|
+
* Optional event callback for driver lifecycle events.
|
|
134
|
+
* Receives structured events for logging to Grafana/Loki/external systems.
|
|
135
|
+
* Called for: session start/end, errors, warnings, USB diagnostics.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* configure({
|
|
140
|
+
* onDriverEvent: (event) => {
|
|
141
|
+
* grafanaLogger.log(event.level, event.message, event.data);
|
|
142
|
+
* }
|
|
143
|
+
* });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
onDriverEvent?: (event: DriverEvent) => void;
|
|
147
|
+
};
|
|
148
|
+
/** Structured event emitted by the driver for external logging/monitoring. */
|
|
149
|
+
type DriverEvent = {
|
|
150
|
+
/** Event severity level. */
|
|
151
|
+
level: "info" | "warn" | "error";
|
|
152
|
+
/** Human-readable event description. */
|
|
153
|
+
message: string;
|
|
154
|
+
/** Event category for filtering. */
|
|
155
|
+
category: "session" | "device" | "usb" | "display" | "signature" | "flash";
|
|
156
|
+
/** Optional structured data payload. */
|
|
157
|
+
data?: Record<string, unknown>;
|
|
158
|
+
/** ISO timestamp. */
|
|
159
|
+
timestamp: string;
|
|
160
|
+
};
|
|
161
|
+
/** Minimal logger interface (compatible with console, electron-log, winston, etc.) */
|
|
162
|
+
interface Logger {
|
|
163
|
+
info(...args: any[]): void;
|
|
164
|
+
warn(...args: any[]): void;
|
|
165
|
+
error(...args: any[]): void;
|
|
166
|
+
debug?(...args: any[]): void;
|
|
167
|
+
}
|
|
168
|
+
/** The public API for the Signotec Pad SDK. */
|
|
169
|
+
interface PadDriver {
|
|
170
|
+
/**
|
|
171
|
+
* Get all connected Signotec signing pads.
|
|
172
|
+
* Returns empty array if no devices found (does NOT throw).
|
|
173
|
+
*/
|
|
174
|
+
getSignotecPads(): DeviceInfo[];
|
|
175
|
+
/**
|
|
176
|
+
* Start a signature capture session on the specified pad.
|
|
177
|
+
* Draws the signing UI (buttons + text), configures hotspots, starts capture.
|
|
178
|
+
*
|
|
179
|
+
* @param serialNo - Serial number of the target pad (from getSignotecPads)
|
|
180
|
+
* @param handlers - Callback handlers for user events and live signature data
|
|
181
|
+
* @param options - Display content and output configuration
|
|
182
|
+
* @throws Error if device cannot be opened or signing session fails to start
|
|
183
|
+
*/
|
|
184
|
+
startSigningProcess(serialNo: string, handlers: SignatureCallbackHandlers, options: StartSignatureOptions): Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Cancel the current signing session.
|
|
187
|
+
* Fires the 'cancel' user event, restores standby display, closes device.
|
|
188
|
+
*/
|
|
189
|
+
cancelSignature(): {
|
|
190
|
+
status: boolean;
|
|
191
|
+
message: string;
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Confirm the current signature.
|
|
195
|
+
* Renders signature as PNG, fires 'confirm' with base64 image, restores standby.
|
|
196
|
+
* @throws Error if no active signing session
|
|
197
|
+
*/
|
|
198
|
+
confirmSignature(): void;
|
|
199
|
+
/**
|
|
200
|
+
* Skip signature and continue without one.
|
|
201
|
+
* Fires 'confirm' with empty base64Img.
|
|
202
|
+
*/
|
|
203
|
+
continueWithoutSignature(): Promise<{
|
|
204
|
+
status: boolean;
|
|
205
|
+
message: string;
|
|
206
|
+
}>;
|
|
207
|
+
/**
|
|
208
|
+
* Store a standby image to the pad's flash memory.
|
|
209
|
+
* The image persists across power cycles and USB disconnects.
|
|
210
|
+
* After each signing session, the standby is automatically restored via 0x8A.
|
|
211
|
+
*
|
|
212
|
+
* @param imagePath - Path to PNG or BMP image (320x160 for Sigma pads), or null to clear
|
|
213
|
+
* @returns true if stored successfully
|
|
214
|
+
*/
|
|
215
|
+
setStandbyImage(imagePath: string | null): Promise<boolean>;
|
|
216
|
+
/**
|
|
217
|
+
* Wait for a Signotec pad to be connected.
|
|
218
|
+
* Polls USB bus until a device appears or timeout expires.
|
|
219
|
+
*
|
|
220
|
+
* @param timeoutMs - Maximum wait time in milliseconds. Default: 30000
|
|
221
|
+
* @returns DeviceInfo of the first device found, or null on timeout
|
|
222
|
+
*/
|
|
223
|
+
waitForDevice?(timeoutMs?: number): Promise<DeviceInfo | null>;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export { DEVICE_TYPE_MAPPINGS, type DeviceInfo, type DisplayLine, type DriverConfig, type DriverEvent, type Logger, type PadDriver, type SignatureCallbackHandlers, type SignatureDisplayData, type SignatureEventHandler, type SignatureEventHandlerLive, type SignatureOutputOptions, type StartSignatureOptions };
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/types.ts
|
|
21
|
+
var types_exports = {};
|
|
22
|
+
__export(types_exports, {
|
|
23
|
+
DEVICE_TYPE_MAPPINGS: () => DEVICE_TYPE_MAPPINGS
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(types_exports);
|
|
26
|
+
var DEVICE_TYPE_MAPPINGS = {
|
|
27
|
+
1: "Sigma USB",
|
|
28
|
+
2: "Sigma seriell",
|
|
29
|
+
5: "Zeta USB",
|
|
30
|
+
6: "Zeta seriell",
|
|
31
|
+
11: "Omega USB",
|
|
32
|
+
12: "Omega seriell",
|
|
33
|
+
15: "Gamma USB",
|
|
34
|
+
16: "Gamma seriell",
|
|
35
|
+
21: "Delta USB",
|
|
36
|
+
22: "Delta seriell",
|
|
37
|
+
23: "Delta IP",
|
|
38
|
+
31: "Alpha USB",
|
|
39
|
+
32: "Alpha seriell",
|
|
40
|
+
33: "Alpha IP"
|
|
41
|
+
};
|
|
42
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
43
|
+
0 && (module.exports = {
|
|
44
|
+
DEVICE_TYPE_MAPPINGS
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=types.js.map
|