scan2form 1.2.3 → 1.2.4
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/dist/bridge-server.js +4 -0
- package/dist/esm/scanner-client.js +16 -78
- package/dist/scanner-client.js +16 -78
- package/package.json +1 -1
package/dist/bridge-server.js
CHANGED
|
@@ -101,6 +101,7 @@ app.post('/scan', async (req, res) => {
|
|
|
101
101
|
(0, child_process_1.exec)(cmd, (error, stdout, stderr) => {
|
|
102
102
|
if (error) {
|
|
103
103
|
console.error(`NAPS2 Error: ${error.message}`);
|
|
104
|
+
// Return the actual error details to the client
|
|
104
105
|
const errorDetail = stderr || error.message;
|
|
105
106
|
return res.status(500).json({ error: "Scan failed", details: errorDetail });
|
|
106
107
|
}
|
|
@@ -118,10 +119,13 @@ app.post('/scan', async (req, res) => {
|
|
|
118
119
|
else if (engine === 'sane') {
|
|
119
120
|
// SANE flow: scanimage -> tiff -> sips -> target format
|
|
120
121
|
const tempTiffPath = path_1.default.join(TEMP_DIR, `scan_${scanId}.tiff`);
|
|
122
|
+
// Default to batch access or single scan. `scanimage --format=tiff > output.tiff`
|
|
121
123
|
const cmd = `scanimage --format=tiff --mode Color --resolution 300 > "${tempTiffPath}"`;
|
|
122
124
|
console.log(`Scanning with SANE: ${cmd}`);
|
|
123
125
|
(0, child_process_1.exec)(cmd, (error, stdout, stderr) => {
|
|
124
126
|
if (error) {
|
|
127
|
+
// scanimage writes progress to stderr, so it might not be a real error unless exit code != 0.
|
|
128
|
+
// But exec gives error on non-zero exit.
|
|
125
129
|
console.error(`SANE Error: ${error.message}`);
|
|
126
130
|
const errorDetail = stderr || error.message;
|
|
127
131
|
return res.status(500).json({ error: "Scan failed", details: errorDetail });
|
|
@@ -26,93 +26,31 @@ export class Scan2Form {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
// Rule 5.2 & 5.3: Trigger Scan & Receive Blob
|
|
29
|
-
async
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
config = { targetInputId: options };
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
config = { ...options };
|
|
37
|
-
}
|
|
38
|
-
// Rule 5.6: Auto-detect format from Input "accept" attribute if not specified
|
|
39
|
-
if (!config.format && config.targetInputId) {
|
|
40
|
-
const input = document.getElementById(config.targetInputId);
|
|
41
|
-
if (input && input.accept) {
|
|
42
|
-
const accept = input.accept.toLowerCase();
|
|
43
|
-
if (accept.includes('image/png')) {
|
|
44
|
-
config.format = 'png';
|
|
45
|
-
}
|
|
46
|
-
else if (accept.includes('image/jpeg') || accept.includes('image/jpg') || accept.includes('image/*')) {
|
|
47
|
-
config.format = 'jpeg'; // Default image format
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
// Default to PDF
|
|
52
|
-
if (!config.format)
|
|
53
|
-
config.format = 'pdf';
|
|
29
|
+
async scanToInput(inputId) {
|
|
30
|
+
const inputElement = document.getElementById(inputId);
|
|
31
|
+
if (!inputElement)
|
|
32
|
+
throw new Error("Input element not found");
|
|
54
33
|
try {
|
|
55
|
-
const response = await fetch(`${this.bridgeUrl}/scan`, {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
body: JSON.stringify({ format: config.format })
|
|
59
|
-
});
|
|
60
|
-
if (!response.ok) {
|
|
61
|
-
const errData = await response.json();
|
|
62
|
-
throw new Error(errData.details || "Scan failed or cancelled");
|
|
63
|
-
}
|
|
34
|
+
const response = await fetch(`${this.bridgeUrl}/scan`, { method: 'POST' });
|
|
35
|
+
if (!response.ok)
|
|
36
|
+
throw new Error("Scan failed or cancelled at device");
|
|
64
37
|
const blob = await response.blob();
|
|
65
|
-
// Determine mime type based on format or blob
|
|
66
|
-
const mimeType = blob.type || (config.format === 'pdf' ? 'application/pdf' : `image/${config.format}`);
|
|
67
38
|
// Rule 5.4: Inject into DataTransfer
|
|
68
|
-
const
|
|
39
|
+
const mimeType = blob.type || 'application/pdf';
|
|
40
|
+
const ext = mimeType === 'image/jpeg' ? 'jpg' : (mimeType.split('/')[1] || 'pdf');
|
|
69
41
|
const file = new File([blob], `scanned_doc_${Date.now()}.${ext}`, { type: mimeType });
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
dataTransfer.items.add(file);
|
|
76
|
-
inputElement.files = dataTransfer.files;
|
|
77
|
-
inputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
// Handle Preview
|
|
81
|
-
if (config.previewElementId) {
|
|
82
|
-
this.handlePreview(config.previewElementId, file);
|
|
83
|
-
}
|
|
42
|
+
const dataTransfer = new DataTransfer();
|
|
43
|
+
dataTransfer.items.add(file);
|
|
44
|
+
inputElement.files = dataTransfer.files;
|
|
45
|
+
// Trigger change event so frameworks (React/Vue) detect the update
|
|
46
|
+
inputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
84
47
|
return { success: true, file: file };
|
|
85
48
|
}
|
|
86
49
|
catch (error) {
|
|
87
50
|
console.error("Scan2Form Error:", error);
|
|
51
|
+
// Alerting might be annoying in a library, maybe optional? Leaving as is for now but usually libraries shouldn't alert.
|
|
52
|
+
// alert("Ensure Scan2Form Bridge is running!");
|
|
88
53
|
return { success: false, error: error.message || "An unknown error occurred during scan." };
|
|
89
54
|
}
|
|
90
55
|
}
|
|
91
|
-
/**
|
|
92
|
-
* Alias for scan() to maintain backward compatibility, but now supports options.
|
|
93
|
-
*/
|
|
94
|
-
async scanToInput(inputIdOrOptions) {
|
|
95
|
-
return this.scan(inputIdOrOptions);
|
|
96
|
-
}
|
|
97
|
-
handlePreview(elementId, file) {
|
|
98
|
-
const el = document.getElementById(elementId);
|
|
99
|
-
if (!el)
|
|
100
|
-
return;
|
|
101
|
-
const url = URL.createObjectURL(file);
|
|
102
|
-
const tagName = el.tagName.toLowerCase();
|
|
103
|
-
if (tagName === 'img') {
|
|
104
|
-
el.src = url;
|
|
105
|
-
}
|
|
106
|
-
else if (tagName === 'iframe') {
|
|
107
|
-
el.src = url;
|
|
108
|
-
}
|
|
109
|
-
else if (tagName === 'embed') {
|
|
110
|
-
el.src = url;
|
|
111
|
-
el.type = file.type;
|
|
112
|
-
}
|
|
113
|
-
else if (tagName === 'object') {
|
|
114
|
-
el.data = url;
|
|
115
|
-
el.type = file.type;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
56
|
}
|
package/dist/scanner-client.js
CHANGED
|
@@ -29,94 +29,32 @@ class Scan2Form {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
// Rule 5.2 & 5.3: Trigger Scan & Receive Blob
|
|
32
|
-
async
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
config = { targetInputId: options };
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
config = { ...options };
|
|
40
|
-
}
|
|
41
|
-
// Rule 5.6: Auto-detect format from Input "accept" attribute if not specified
|
|
42
|
-
if (!config.format && config.targetInputId) {
|
|
43
|
-
const input = document.getElementById(config.targetInputId);
|
|
44
|
-
if (input && input.accept) {
|
|
45
|
-
const accept = input.accept.toLowerCase();
|
|
46
|
-
if (accept.includes('image/png')) {
|
|
47
|
-
config.format = 'png';
|
|
48
|
-
}
|
|
49
|
-
else if (accept.includes('image/jpeg') || accept.includes('image/jpg') || accept.includes('image/*')) {
|
|
50
|
-
config.format = 'jpeg'; // Default image format
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
// Default to PDF
|
|
55
|
-
if (!config.format)
|
|
56
|
-
config.format = 'pdf';
|
|
32
|
+
async scanToInput(inputId) {
|
|
33
|
+
const inputElement = document.getElementById(inputId);
|
|
34
|
+
if (!inputElement)
|
|
35
|
+
throw new Error("Input element not found");
|
|
57
36
|
try {
|
|
58
|
-
const response = await fetch(`${this.bridgeUrl}/scan`, {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
body: JSON.stringify({ format: config.format })
|
|
62
|
-
});
|
|
63
|
-
if (!response.ok) {
|
|
64
|
-
const errData = await response.json();
|
|
65
|
-
throw new Error(errData.details || "Scan failed or cancelled");
|
|
66
|
-
}
|
|
37
|
+
const response = await fetch(`${this.bridgeUrl}/scan`, { method: 'POST' });
|
|
38
|
+
if (!response.ok)
|
|
39
|
+
throw new Error("Scan failed or cancelled at device");
|
|
67
40
|
const blob = await response.blob();
|
|
68
|
-
// Determine mime type based on format or blob
|
|
69
|
-
const mimeType = blob.type || (config.format === 'pdf' ? 'application/pdf' : `image/${config.format}`);
|
|
70
41
|
// Rule 5.4: Inject into DataTransfer
|
|
71
|
-
const
|
|
42
|
+
const mimeType = blob.type || 'application/pdf';
|
|
43
|
+
const ext = mimeType === 'image/jpeg' ? 'jpg' : (mimeType.split('/')[1] || 'pdf');
|
|
72
44
|
const file = new File([blob], `scanned_doc_${Date.now()}.${ext}`, { type: mimeType });
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
dataTransfer.items.add(file);
|
|
79
|
-
inputElement.files = dataTransfer.files;
|
|
80
|
-
inputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
// Handle Preview
|
|
84
|
-
if (config.previewElementId) {
|
|
85
|
-
this.handlePreview(config.previewElementId, file);
|
|
86
|
-
}
|
|
45
|
+
const dataTransfer = new DataTransfer();
|
|
46
|
+
dataTransfer.items.add(file);
|
|
47
|
+
inputElement.files = dataTransfer.files;
|
|
48
|
+
// Trigger change event so frameworks (React/Vue) detect the update
|
|
49
|
+
inputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
87
50
|
return { success: true, file: file };
|
|
88
51
|
}
|
|
89
52
|
catch (error) {
|
|
90
53
|
console.error("Scan2Form Error:", error);
|
|
54
|
+
// Alerting might be annoying in a library, maybe optional? Leaving as is for now but usually libraries shouldn't alert.
|
|
55
|
+
// alert("Ensure Scan2Form Bridge is running!");
|
|
91
56
|
return { success: false, error: error.message || "An unknown error occurred during scan." };
|
|
92
57
|
}
|
|
93
58
|
}
|
|
94
|
-
/**
|
|
95
|
-
* Alias for scan() to maintain backward compatibility, but now supports options.
|
|
96
|
-
*/
|
|
97
|
-
async scanToInput(inputIdOrOptions) {
|
|
98
|
-
return this.scan(inputIdOrOptions);
|
|
99
|
-
}
|
|
100
|
-
handlePreview(elementId, file) {
|
|
101
|
-
const el = document.getElementById(elementId);
|
|
102
|
-
if (!el)
|
|
103
|
-
return;
|
|
104
|
-
const url = URL.createObjectURL(file);
|
|
105
|
-
const tagName = el.tagName.toLowerCase();
|
|
106
|
-
if (tagName === 'img') {
|
|
107
|
-
el.src = url;
|
|
108
|
-
}
|
|
109
|
-
else if (tagName === 'iframe') {
|
|
110
|
-
el.src = url;
|
|
111
|
-
}
|
|
112
|
-
else if (tagName === 'embed') {
|
|
113
|
-
el.src = url;
|
|
114
|
-
el.type = file.type;
|
|
115
|
-
}
|
|
116
|
-
else if (tagName === 'object') {
|
|
117
|
-
el.data = url;
|
|
118
|
-
el.type = file.type;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
59
|
}
|
|
122
60
|
exports.Scan2Form = Scan2Form;
|