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.
@@ -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 scan(options) {
30
- // Backward compatibility: if string, treat as inputId
31
- let config = {};
32
- if (typeof options === 'string') {
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
- method: 'POST',
57
- headers: { 'Content-Type': 'application/json' },
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 ext = config.format === 'jpeg' ? 'jpg' : config.format;
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
- // Handle Input Population
71
- if (config.targetInputId) {
72
- const inputElement = document.getElementById(config.targetInputId);
73
- if (inputElement) {
74
- const dataTransfer = new DataTransfer();
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
  }
@@ -29,94 +29,32 @@ class Scan2Form {
29
29
  }
30
30
  }
31
31
  // Rule 5.2 & 5.3: Trigger Scan & Receive Blob
32
- async scan(options) {
33
- // Backward compatibility: if string, treat as inputId
34
- let config = {};
35
- if (typeof options === 'string') {
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
- method: 'POST',
60
- headers: { 'Content-Type': 'application/json' },
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 ext = config.format === 'jpeg' ? 'jpg' : config.format;
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
- // Handle Input Population
74
- if (config.targetInputId) {
75
- const inputElement = document.getElementById(config.targetInputId);
76
- if (inputElement) {
77
- const dataTransfer = new DataTransfer();
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scan2form",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "Local offline bridge allowing web browsers to access physical scanners (WIA, TWAIN, SANE).",
5
5
  "main": "dist/scanner-client.js",
6
6
  "scripts": {