scanonweb 1.0.2 → 2.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 +119 -140
- package/dist/index.d.ts +180 -0
- package/dist/scanonweb.cjs.js +294 -468
- package/dist/scanonweb.esm.js +294 -468
- package/dist/scanonweb.umd.js +294 -468
- package/dist/scanonweb.umd.min.js +4 -4
- package/package.json +4 -3
- package/src/index.d.ts +114 -200
- package/src/index.js +375 -422
package/dist/scanonweb.esm.js
CHANGED
|
@@ -1,63 +1,38 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* scanonweb
|
|
3
|
-
* ScanOnWeb - 扫描控件 JavaScript SDK
|
|
2
|
+
* scanonweb v2.0.0
|
|
3
|
+
* ScanOnWeb - 扫描控件 JavaScript SDK,支持 v2 协议、scanSource 和增量图像事件
|
|
4
4
|
* https://www.brainysoft.cn
|
|
5
5
|
*
|
|
6
|
-
* Copyright (c)
|
|
6
|
+
* Copyright (c) 2026 BrainySoft
|
|
7
7
|
* Licensed under the MIT license
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
|
-
* ScanOnWeb -
|
|
11
|
-
* https://www.brainysoft.cn
|
|
12
|
-
* @version
|
|
13
|
-
* @author BrainySoft
|
|
14
|
-
* @license MIT
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 扫描控件类 - 用于与本地扫描服务程序通信
|
|
19
|
-
* @class ScanOnWeb
|
|
10
|
+
* ScanOnWeb - JavaScript SDK for the local ScanOnWeb tray service.
|
|
11
|
+
* https://www.brainysoft.cn
|
|
12
|
+
* @version 2.0.0
|
|
20
13
|
*/
|
|
21
14
|
class ScanOnWeb {
|
|
22
15
|
constructor() {
|
|
23
|
-
|
|
16
|
+
this.protocolVersion = 2;
|
|
17
|
+
this.serverProtocolVersion = null;
|
|
18
|
+
this.imageCount = 0;
|
|
24
19
|
this.scaner_work_config = {
|
|
25
20
|
showUI: false,
|
|
26
|
-
// 是否显示扫描控件工作界面,如果为false则不显示扫描控件工作界面
|
|
27
21
|
dpi_x: 300,
|
|
28
|
-
// dpi 分辨率x,一般的图像扫描300dpi就够了
|
|
29
22
|
dpi_y: 300,
|
|
30
|
-
// dpi 分辨率y
|
|
31
23
|
deviceIndex: 0,
|
|
32
|
-
// 选中的扫描仪硬件设备id索引,如果有多个扫描仪设备,这个值就是用来选择哪个设备进行扫描的
|
|
33
24
|
showDialog: false,
|
|
34
|
-
|
|
35
|
-
autoFeedEnable: true,
|
|
36
|
-
// 是否使用自动进纸器(需要设备支持才能正常工作)
|
|
25
|
+
scanSource: "flatbed",
|
|
37
26
|
autoFeed: false,
|
|
38
|
-
// 是否自动装填纸张(需要设备支持才能正常工作)
|
|
39
27
|
dupxMode: false,
|
|
40
|
-
// 是否使用双面扫描模式(需要设备支持才能正常工作)
|
|
41
28
|
autoDeskew: false,
|
|
42
|
-
// 是否使用自动纠偏模式(需要设备支持才能正常工作)
|
|
43
29
|
autoBorderDetection: false,
|
|
44
|
-
// 是否使用自动边框检测(需要设备支持才能正常工作)
|
|
45
30
|
colorMode: "RGB",
|
|
46
|
-
|
|
47
|
-
transMode: "memory" // 数据传输模式,memory,file,native 这三种配置值,默认为memory模式,大部分设备都是使用这种模式
|
|
31
|
+
transMode: "memory"
|
|
48
32
|
};
|
|
49
33
|
this.h5socket = null;
|
|
50
|
-
this.imageCount = 0; // 扫描结果图像总数
|
|
51
|
-
|
|
52
|
-
// 尝试连接websocket服务器,注意连接成功哪个是通过回调实现的
|
|
53
34
|
this.tryConnect();
|
|
54
35
|
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* 通过连接多个websocket server端口返回一个可用的websocket连接对象,主要用于防止本地端口被占用的情况
|
|
58
|
-
* @param {string[]} wssUrls - WebSocket服务器URL数组
|
|
59
|
-
* @returns {Promise} WebSocket连接Promise
|
|
60
|
-
*/
|
|
61
36
|
getConnectedServer(wssUrls) {
|
|
62
37
|
console.log("尝试连接托盘扫描服务websocket服务器...");
|
|
63
38
|
return new Promise((resolve, reject) => {
|
|
@@ -70,225 +45,239 @@ class ScanOnWeb {
|
|
|
70
45
|
};
|
|
71
46
|
}).then(server => {
|
|
72
47
|
console.log("连接websocket服务器成功!");
|
|
73
|
-
// 找到了可用websocket服务器端口
|
|
74
48
|
this.initWebsocketCallback(server);
|
|
75
49
|
console.log("尝试获取扫描设备列表...");
|
|
76
|
-
// 发送一个获取扫描设备列表的命令,询问本地计算机安装了多少个扫描设备的驱动程序
|
|
77
50
|
this.loadDevices();
|
|
78
51
|
return server;
|
|
79
52
|
}, err => {
|
|
80
|
-
// 如果连接失败,则尝试连接其他端口
|
|
81
53
|
if (wssUrls.length > 1) {
|
|
82
54
|
return this.getConnectedServer(wssUrls.slice(1));
|
|
83
55
|
}
|
|
84
56
|
throw err;
|
|
85
57
|
});
|
|
86
58
|
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* 尝试检测websocket哪个端口可以成功连接
|
|
90
|
-
*/
|
|
91
59
|
tryConnect() {
|
|
92
|
-
// 以下一共定义了5个websocket端口,如果有端口被占用,则会自动尝试连接下一个端口
|
|
93
60
|
const wssUrls = ["ws://127.0.0.1:1001", "ws://127.0.0.1:2001", "ws://127.0.0.1:3001", "ws://127.0.0.1:4001", "ws://127.0.0.1:5001"];
|
|
94
61
|
this.getConnectedServer(wssUrls);
|
|
95
62
|
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* 初始化websocket相关的函数绑定
|
|
99
|
-
* @param {WebSocket} server - WebSocket服务器实例
|
|
100
|
-
*/
|
|
101
63
|
initWebsocketCallback(server) {
|
|
102
64
|
this.h5socket = server;
|
|
103
65
|
this.h5socket.onerror = this.onSocketError.bind(this);
|
|
104
66
|
this.h5socket.onmessage = this.onSocketMessage.bind(this);
|
|
105
67
|
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* WebSocket错误处理
|
|
109
|
-
* @param {Event} event - 错误事件
|
|
110
|
-
*/
|
|
111
68
|
onSocketError(event) {
|
|
112
69
|
alert("无法连接扫描服务程序,请检查扫描服务程序是否已经启动!");
|
|
113
70
|
console.log("WebSocket error: " + event.data);
|
|
114
71
|
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* 判断回调函数是否存在
|
|
118
|
-
* @param {Function} f - 要检查的函数
|
|
119
|
-
* @returns {boolean} 函数是否存在且为函数类型
|
|
120
|
-
*/
|
|
121
72
|
isCallbackExist(f) {
|
|
122
73
|
if (!f || typeof f === "undefined" || f === undefined) {
|
|
123
74
|
return false;
|
|
124
75
|
}
|
|
125
76
|
return typeof f === "function";
|
|
126
77
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
78
|
+
dispatchCallback(name, msg) {
|
|
79
|
+
if (this.isCallbackExist(this[name])) {
|
|
80
|
+
this[name](msg);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
toBoolCompat(value) {
|
|
84
|
+
if (typeof value === "boolean") {
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
if (typeof value === "number") {
|
|
88
|
+
return value !== 0;
|
|
89
|
+
}
|
|
90
|
+
if (typeof value === "string") {
|
|
91
|
+
const normalized = value.trim().toLowerCase();
|
|
92
|
+
return ["1", "true", "yes", "y", "on", "adf"].includes(normalized);
|
|
93
|
+
}
|
|
94
|
+
return !!value;
|
|
95
|
+
}
|
|
96
|
+
toIntCompat(value, fallback) {
|
|
97
|
+
const parsed = Number(value);
|
|
98
|
+
return Number.isInteger(parsed) ? parsed : fallback;
|
|
99
|
+
}
|
|
100
|
+
normalizeScanSource(scanSource, legacyAutoFeedEnable) {
|
|
101
|
+
if (typeof scanSource === "string") {
|
|
102
|
+
const normalized = scanSource.trim().toLowerCase();
|
|
103
|
+
if (normalized === "adf" || normalized === "feeder" || normalized === "documentfeeder" || normalized === "document_feeder" || normalized === "automatic_document_feeder") {
|
|
104
|
+
return "adf";
|
|
105
|
+
}
|
|
106
|
+
if (normalized === "flatbed" || normalized === "flat_bed" || normalized === "platen") {
|
|
107
|
+
return "flatbed";
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (this.toBoolCompat(legacyAutoFeedEnable)) {
|
|
111
|
+
return "adf";
|
|
112
|
+
}
|
|
113
|
+
return "flatbed";
|
|
114
|
+
}
|
|
115
|
+
getLegacyAutoFeedEnable(scanSource) {
|
|
116
|
+
return this.normalizeScanSource(scanSource) === "adf";
|
|
117
|
+
}
|
|
118
|
+
shouldIncludeLegacyAutoFeedEnable() {
|
|
119
|
+
return this.serverProtocolVersion === null || this.serverProtocolVersion < 2;
|
|
120
|
+
}
|
|
121
|
+
normalizeScanConfig(config, options) {
|
|
122
|
+
const merged = Object.assign({}, this.scaner_work_config, config || {});
|
|
123
|
+
const includeLegacyAutoFeedEnable = !options || options.includeLegacyAutoFeedEnable !== false;
|
|
124
|
+
const normalized = {
|
|
125
|
+
showUI: this.toBoolCompat(merged.showUI),
|
|
126
|
+
dpi_x: this.toIntCompat(merged.dpi_x, 300),
|
|
127
|
+
dpi_y: this.toIntCompat(merged.dpi_y, 300),
|
|
128
|
+
deviceIndex: this.toIntCompat(merged.deviceIndex, 0),
|
|
129
|
+
showDialog: this.toBoolCompat(merged.showDialog),
|
|
130
|
+
scanSource: this.normalizeScanSource(merged.scanSource, merged.autoFeedEnable),
|
|
131
|
+
autoFeed: this.toBoolCompat(merged.autoFeed),
|
|
132
|
+
dupxMode: this.toBoolCompat(merged.dupxMode),
|
|
133
|
+
autoDeskew: this.toBoolCompat(merged.autoDeskew),
|
|
134
|
+
autoBorderDetection: this.toBoolCompat(merged.autoBorderDetection),
|
|
135
|
+
colorMode: merged.colorMode || "RGB",
|
|
136
|
+
transMode: merged.transMode || "memory"
|
|
137
|
+
};
|
|
138
|
+
if (includeLegacyAutoFeedEnable) {
|
|
139
|
+
normalized.autoFeedEnable = this.getLegacyAutoFeedEnable(normalized.scanSource);
|
|
140
|
+
}
|
|
141
|
+
return normalized;
|
|
142
|
+
}
|
|
143
|
+
recordServerProtocolVersion(msg) {
|
|
144
|
+
const version = this.toIntCompat(msg && msg.protocolVersion, 1);
|
|
145
|
+
this.serverProtocolVersion = version;
|
|
146
|
+
return version;
|
|
147
|
+
}
|
|
148
|
+
applyIncomingScanConfig(msg) {
|
|
149
|
+
this.scaner_work_config.deviceIndex = this.toIntCompat(msg.currentIndex, this.scaner_work_config.deviceIndex);
|
|
150
|
+
if (Object.prototype.hasOwnProperty.call(msg, "showDialog")) {
|
|
151
|
+
this.scaner_work_config.showDialog = this.toBoolCompat(msg.showDialog);
|
|
152
|
+
}
|
|
153
|
+
this.scaner_work_config.scanSource = this.normalizeScanSource(msg.scanSource, msg.autoFeedEnable);
|
|
154
|
+
if (Object.prototype.hasOwnProperty.call(msg, "autoFeed")) {
|
|
155
|
+
this.scaner_work_config.autoFeed = this.toBoolCompat(msg.autoFeed);
|
|
156
|
+
}
|
|
157
|
+
if (Object.prototype.hasOwnProperty.call(msg, "dupxMode")) {
|
|
158
|
+
this.scaner_work_config.dupxMode = this.toBoolCompat(msg.dupxMode);
|
|
159
|
+
}
|
|
160
|
+
if (Object.prototype.hasOwnProperty.call(msg, "autoDeskew")) {
|
|
161
|
+
this.scaner_work_config.autoDeskew = this.toBoolCompat(msg.autoDeskew);
|
|
162
|
+
}
|
|
163
|
+
if (Object.prototype.hasOwnProperty.call(msg, "autoBorderDetection")) {
|
|
164
|
+
this.scaner_work_config.autoBorderDetection = this.toBoolCompat(msg.autoBorderDetection);
|
|
165
|
+
}
|
|
166
|
+
if (typeof msg.colorMode === "string" && msg.colorMode) {
|
|
167
|
+
this.scaner_work_config.colorMode = msg.colorMode;
|
|
168
|
+
}
|
|
169
|
+
if (typeof msg.transMode === "string" && msg.transMode) {
|
|
170
|
+
this.scaner_work_config.transMode = msg.transMode;
|
|
171
|
+
}
|
|
172
|
+
this.scaner_work_config.autoFeedEnable = this.getLegacyAutoFeedEnable(this.scaner_work_config.scanSource);
|
|
173
|
+
}
|
|
174
|
+
normalizeIncomingMessage(rawMsg) {
|
|
175
|
+
const msg = Object.assign({}, rawMsg || {});
|
|
176
|
+
const protocolVersion = this.recordServerProtocolVersion(msg);
|
|
177
|
+
const rawType = typeof msg.cmd_type === "string" ? msg.cmd_type : "";
|
|
178
|
+
if (!msg.scanSource) {
|
|
179
|
+
msg.scanSource = this.normalizeScanSource(msg.scanSource, msg.autoFeedEnable);
|
|
180
|
+
}
|
|
181
|
+
switch (rawType) {
|
|
182
|
+
case "getAllImage":
|
|
183
|
+
msg.cmd_type = "imageListSnapshot";
|
|
184
|
+
break;
|
|
185
|
+
case "getImageById":
|
|
186
|
+
msg.cmd_type = "imageSnapshot";
|
|
187
|
+
break;
|
|
188
|
+
case "imageDrap":
|
|
189
|
+
msg.cmd_type = "imageMoved";
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
if (!msg.protocolVersion) {
|
|
193
|
+
msg.protocolVersion = protocolVersion;
|
|
194
|
+
}
|
|
195
|
+
return msg;
|
|
196
|
+
}
|
|
132
197
|
onSocketMessage(event) {
|
|
133
|
-
const
|
|
134
|
-
|
|
198
|
+
const rawMsg = JSON.parse(event.data);
|
|
199
|
+
const msg = this.normalizeIncomingMessage(rawMsg);
|
|
200
|
+
if (typeof msg.imageCount === "number") {
|
|
201
|
+
this.imageCount = msg.imageCount;
|
|
202
|
+
}
|
|
135
203
|
switch (msg.cmd_type) {
|
|
136
204
|
case "getDevicesList":
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if (this.isCallbackExist(this.onGetDevicesListEvent)) {
|
|
140
|
-
this.onGetDevicesListEvent(msg);
|
|
141
|
-
}
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
205
|
+
this.dispatchCallback("onGetDevicesListEvent", msg);
|
|
206
|
+
break;
|
|
144
207
|
case "scanComplete":
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
this.imageCount = msg.imageCount;
|
|
148
|
-
if (this.isCallbackExist(this.onScanFinishedEvent)) {
|
|
149
|
-
this.onScanFinishedEvent(msg);
|
|
150
|
-
}
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
208
|
+
this.dispatchCallback("onScanFinishedEvent", msg);
|
|
209
|
+
break;
|
|
153
210
|
case "selectScanDevice":
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
this.scaner_work_config.showDialog = msg.showDialog; // 是否显示设备内置对话框
|
|
158
|
-
this.scaner_work_config.autoFeedEnable = msg.autoFeedEnable; // 是否使用自动进纸器(需要设备支持才能正常工作)
|
|
159
|
-
this.scaner_work_config.autoFeed = msg.autoFeed; // 是否自动装填纸张(需要设备支持才能正常工作)
|
|
160
|
-
this.scaner_work_config.dupxMode = msg.dupxMode; // 是否使用双面扫描模式(需要设备支持才能正常工作)
|
|
161
|
-
this.scaner_work_config.autoDeskew = msg.autoDeskew; // 是否使用自动纠偏模式(需要设备支持才能正常工作)
|
|
162
|
-
this.scaner_work_config.autoBorderDetection = msg.autoBorderDetection; // 是否使用自动边框检测(需要设备支持才能正常工作)
|
|
163
|
-
|
|
164
|
-
if (this.isCallbackExist(this.onSelectScanDeviceEvent)) {
|
|
165
|
-
this.onSelectScanDeviceEvent(msg);
|
|
166
|
-
}
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
211
|
+
this.applyIncomingScanConfig(msg);
|
|
212
|
+
this.dispatchCallback("onSelectScanDeviceEvent", msg);
|
|
213
|
+
break;
|
|
169
214
|
case "getImageCount":
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
this.onGetAllImageEvent(msg);
|
|
184
|
-
}
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
case "getImageById":
|
|
188
|
-
{
|
|
189
|
-
// 获取某一页图片的base64编码数据
|
|
190
|
-
this.imageCount = msg.imageCount;
|
|
191
|
-
if (this.isCallbackExist(this.onGetImageByIdEvent)) {
|
|
192
|
-
this.onGetImageByIdEvent(msg);
|
|
193
|
-
}
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
215
|
+
this.dispatchCallback("onGetImageCountEvent", msg);
|
|
216
|
+
break;
|
|
217
|
+
case "imageListSnapshot":
|
|
218
|
+
this.dispatchCallback("onImageListSnapshotEvent", msg);
|
|
219
|
+
this.dispatchCallback("onGetAllImageEvent", msg);
|
|
220
|
+
break;
|
|
221
|
+
case "imageSnapshot":
|
|
222
|
+
this.dispatchCallback("onImageSnapshotEvent", msg);
|
|
223
|
+
this.dispatchCallback("onGetImageByIdEvent", msg);
|
|
224
|
+
break;
|
|
225
|
+
case "scanPageAdded":
|
|
226
|
+
this.dispatchCallback("onScanPageAddedEvent", msg);
|
|
227
|
+
break;
|
|
196
228
|
case "loadImageFromUrl":
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
this.imageCount = msg.imageCount;
|
|
200
|
-
if (this.isCallbackExist(this.onLoadImageFromUrlEvent)) {
|
|
201
|
-
this.onLoadImageFromUrlEvent(msg);
|
|
202
|
-
}
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
229
|
+
this.dispatchCallback("onLoadImageFromUrlEvent", msg);
|
|
230
|
+
break;
|
|
205
231
|
case "loadImageFromBase64":
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
this.imageCount = msg.imageCount;
|
|
209
|
-
if (this.isCallbackExist(this.onLoadImageFromBase64Event)) {
|
|
210
|
-
this.onLoadImageFromBase64Event(msg);
|
|
211
|
-
}
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
232
|
+
this.dispatchCallback("onLoadImageFromBase64Event", msg);
|
|
233
|
+
break;
|
|
214
234
|
case "rotateImage":
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
this.imageCount = msg.imageCount;
|
|
218
|
-
if (this.isCallbackExist(this.onRotateImageEvent)) {
|
|
219
|
-
this.onRotateImageEvent(msg);
|
|
220
|
-
}
|
|
221
|
-
break;
|
|
222
|
-
}
|
|
235
|
+
this.dispatchCallback("onRotateImageEvent", msg);
|
|
236
|
+
break;
|
|
223
237
|
case "getImageSize":
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
this.imageCount = msg.imageCount;
|
|
227
|
-
if (this.isCallbackExist(this.onGetImageSizeEvent)) {
|
|
228
|
-
this.onGetImageSizeEvent(msg);
|
|
229
|
-
}
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
238
|
+
this.dispatchCallback("onGetImageSizeEvent", msg);
|
|
239
|
+
break;
|
|
232
240
|
case "uploadAllImageAsPdfToUrl":
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (this.isCallbackExist(this.onUploadAllImageAsPdfToUrlEvent)) {
|
|
236
|
-
this.onUploadAllImageAsPdfToUrlEvent(msg);
|
|
237
|
-
}
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
241
|
+
this.dispatchCallback("onUploadAllImageAsPdfToUrlEvent", msg);
|
|
242
|
+
break;
|
|
240
243
|
case "uploadAllImageAsTiffToUrl":
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (this.isCallbackExist(this.onUploadAllImageAsTiffToUrlEvent)) {
|
|
244
|
-
this.onUploadAllImageAsTiffToUrlEvent(msg);
|
|
245
|
-
}
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
244
|
+
this.dispatchCallback("onUploadAllImageAsTiffToUrlEvent", msg);
|
|
245
|
+
break;
|
|
248
246
|
case "uploadJpgImageByIndex":
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (this.isCallbackExist(this.onUploadJpgImageByIndexEvent)) {
|
|
252
|
-
this.onUploadJpgImageByIndexEvent(msg);
|
|
253
|
-
}
|
|
254
|
-
break;
|
|
255
|
-
}
|
|
247
|
+
this.dispatchCallback("onUploadJpgImageByIndexEvent", msg);
|
|
248
|
+
break;
|
|
256
249
|
case "upload":
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// 用户点击了界面里面的"开始上传"按钮的时间回调
|
|
260
|
-
if (this.isCallbackExist(this.onUploadEvent)) {
|
|
261
|
-
this.onUploadEvent(msg);
|
|
262
|
-
}
|
|
263
|
-
break;
|
|
264
|
-
}
|
|
250
|
+
this.dispatchCallback("onUploadEvent", msg);
|
|
251
|
+
break;
|
|
265
252
|
case "imageEdited":
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
break;
|
|
280
|
-
}
|
|
253
|
+
this.dispatchCallback("onImageEditedEvent", msg);
|
|
254
|
+
break;
|
|
255
|
+
case "imageMoved":
|
|
256
|
+
this.dispatchCallback("onImageMovedEvent", msg);
|
|
257
|
+
this.dispatchCallback("onImageDrapEvent", msg);
|
|
258
|
+
break;
|
|
259
|
+
case "imageDeleted":
|
|
260
|
+
this.dispatchCallback("onImageDeletedEvent", msg);
|
|
261
|
+
break;
|
|
262
|
+
case "imagesCleared":
|
|
263
|
+
this.dispatchCallback("onImagesClearedEvent", msg);
|
|
264
|
+
break;
|
|
281
265
|
}
|
|
282
266
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
267
|
+
normalizeOutgoingCommand(commandData) {
|
|
268
|
+
const cmd = Object.assign({}, commandData || {});
|
|
269
|
+
cmd.protocolVersion = this.protocolVersion;
|
|
270
|
+
if (cmd.cmd_type === "startScan") {
|
|
271
|
+
cmd.config = this.normalizeScanConfig(cmd.config || this.scaner_work_config, {
|
|
272
|
+
includeLegacyAutoFeedEnable: this.shouldIncludeLegacyAutoFeedEnable()
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return cmd;
|
|
276
|
+
}
|
|
288
277
|
sendWebSocketCommand(commandData) {
|
|
289
278
|
try {
|
|
290
|
-
if (this.h5socket.readyState === 1) {
|
|
291
|
-
this.h5socket.send(JSON.stringify(commandData));
|
|
279
|
+
if (this.h5socket && this.h5socket.readyState === 1) {
|
|
280
|
+
this.h5socket.send(JSON.stringify(this.normalizeOutgoingCommand(commandData)));
|
|
292
281
|
} else {
|
|
293
282
|
alert("发送扫描指令失败!请刷新页面或者检查托盘扫描程序是否已经正常运行!");
|
|
294
283
|
}
|
|
@@ -296,277 +285,166 @@ class ScanOnWeb {
|
|
|
296
285
|
alert("发送扫描指令失败!" + e);
|
|
297
286
|
}
|
|
298
287
|
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* 设置授权信息
|
|
302
|
-
* @param {string} licenseMode - 授权模式
|
|
303
|
-
* @param {string} key1 - 授权密钥1
|
|
304
|
-
* @param {string} key2 - 授权密钥2
|
|
305
|
-
* @param {string} licenseServerUrl - 授权服务器URL
|
|
306
|
-
*/
|
|
307
288
|
setLicenseKey(licenseMode, key1, key2, licenseServerUrl) {
|
|
308
|
-
|
|
289
|
+
this.sendWebSocketCommand({
|
|
309
290
|
cmd_type: "setLicenseKey",
|
|
310
291
|
licenseMode: licenseMode,
|
|
311
292
|
key1: key1,
|
|
312
293
|
key2: key2,
|
|
313
294
|
url: licenseServerUrl
|
|
314
|
-
};
|
|
315
|
-
this.sendWebSocketCommand(cmdObj);
|
|
295
|
+
});
|
|
316
296
|
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* 加载所有可用的扫描设备
|
|
320
|
-
*/
|
|
321
297
|
loadDevices() {
|
|
322
|
-
|
|
298
|
+
this.sendWebSocketCommand({
|
|
323
299
|
cmd_type: "getDevicesList"
|
|
324
|
-
};
|
|
325
|
-
this.sendWebSocketCommand(cmdObj);
|
|
300
|
+
});
|
|
326
301
|
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* 设置当前选中的扫描设备id
|
|
330
|
-
* @param {number} deviceIndex - 设备索引
|
|
331
|
-
*/
|
|
332
302
|
selectScanDevice(deviceIndex) {
|
|
333
|
-
|
|
303
|
+
this.sendWebSocketCommand({
|
|
334
304
|
cmd_type: "selectScanDevice",
|
|
335
305
|
deviceIndex: deviceIndex
|
|
336
|
-
};
|
|
337
|
-
this.sendWebSocketCommand(cmdObj);
|
|
306
|
+
});
|
|
338
307
|
}
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* 开始扫描
|
|
342
|
-
*/
|
|
343
308
|
startScan() {
|
|
344
|
-
|
|
309
|
+
this.sendWebSocketCommand({
|
|
345
310
|
cmd_type: "startScan",
|
|
346
311
|
config: this.scaner_work_config
|
|
347
|
-
};
|
|
348
|
-
this.sendWebSocketCommand(cmdObj);
|
|
312
|
+
});
|
|
349
313
|
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* 清除全部扫描结果
|
|
353
|
-
*/
|
|
354
314
|
clearAll() {
|
|
355
|
-
|
|
315
|
+
this.sendWebSocketCommand({
|
|
356
316
|
cmd_type: "clearAll"
|
|
357
|
-
};
|
|
358
|
-
this.sendWebSocketCommand(cmdObj);
|
|
317
|
+
});
|
|
359
318
|
}
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* 获取图像总数
|
|
363
|
-
*/
|
|
364
319
|
getImageCount() {
|
|
365
|
-
|
|
320
|
+
this.sendWebSocketCommand({
|
|
366
321
|
cmd_type: "getImageCount"
|
|
367
|
-
};
|
|
368
|
-
this.sendWebSocketCommand(cmdObj);
|
|
322
|
+
});
|
|
369
323
|
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* 获取所有图像
|
|
373
|
-
*/
|
|
374
324
|
getAllImage() {
|
|
375
|
-
|
|
325
|
+
this.sendWebSocketCommand({
|
|
376
326
|
cmd_type: "getAllImage"
|
|
377
|
-
};
|
|
378
|
-
this.sendWebSocketCommand(cmdObj);
|
|
327
|
+
});
|
|
379
328
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
* @param {number} index - 图像索引
|
|
384
|
-
*/
|
|
385
|
-
getImageById(index) {
|
|
386
|
-
const cmdObj = {
|
|
387
|
-
cmd_type: "getImageById",
|
|
388
|
-
index: index
|
|
329
|
+
getImageById(indexOrImageId) {
|
|
330
|
+
const command = {
|
|
331
|
+
cmd_type: "getImageById"
|
|
389
332
|
};
|
|
390
|
-
|
|
333
|
+
if (typeof indexOrImageId === "string" && indexOrImageId.trim()) {
|
|
334
|
+
command.imageId = indexOrImageId.trim();
|
|
335
|
+
} else {
|
|
336
|
+
command.index = indexOrImageId;
|
|
337
|
+
}
|
|
338
|
+
this.sendWebSocketCommand(command);
|
|
391
339
|
}
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* 发送指令远程加载服务器端的多页图像到托盘服务
|
|
395
|
-
* 支持PDF、TIFF以及常见图像格式(JPG、PNG、BMP等)
|
|
396
|
-
* @param {string} url - 图像URL
|
|
397
|
-
* @param {string} [type] - 可选,指定文件类型:'pdf'、'tiff'、'image',如果不指定则根据URL扩展名自动判断
|
|
398
|
-
*/
|
|
399
340
|
loadImageFromUrl(url, type) {
|
|
400
|
-
// 如果没有指定类型,则根据URL扩展名自动判断
|
|
401
341
|
if (!type) {
|
|
402
|
-
const extension = url.split(
|
|
403
|
-
if (extension ===
|
|
404
|
-
type =
|
|
405
|
-
} else if (extension ===
|
|
406
|
-
type =
|
|
407
|
-
} else if ([
|
|
408
|
-
type =
|
|
342
|
+
const extension = url.split(".").pop().toLowerCase();
|
|
343
|
+
if (extension === "pdf") {
|
|
344
|
+
type = "pdf";
|
|
345
|
+
} else if (extension === "tiff" || extension === "tif") {
|
|
346
|
+
type = "tiff";
|
|
347
|
+
} else if (["jpg", "jpeg", "png", "bmp", "gif", "webp"].includes(extension)) {
|
|
348
|
+
type = "image";
|
|
409
349
|
} else {
|
|
410
|
-
|
|
411
|
-
type = 'image';
|
|
350
|
+
type = "image";
|
|
412
351
|
}
|
|
413
352
|
}
|
|
414
|
-
|
|
353
|
+
this.sendWebSocketCommand({
|
|
415
354
|
cmd_type: "loadImageFromUrl",
|
|
416
355
|
url: url,
|
|
417
356
|
type: type
|
|
418
|
-
};
|
|
419
|
-
this.sendWebSocketCommand(cmdObj);
|
|
357
|
+
});
|
|
420
358
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
*/
|
|
427
|
-
loadImageFromBase64(base64Data, format = 'jpg') {
|
|
428
|
-
// 如果base64数据包含data URL前缀,则去除它
|
|
429
|
-
if (base64Data.startsWith('data:')) {
|
|
430
|
-
const base64Index = base64Data.indexOf('base64,');
|
|
359
|
+
loadImageFromBase64(base64Data, format) {
|
|
360
|
+
let normalizedFormat = format || "jpg";
|
|
361
|
+
let normalizedBase64 = base64Data;
|
|
362
|
+
if (normalizedBase64.startsWith("data:")) {
|
|
363
|
+
const base64Index = normalizedBase64.indexOf("base64,");
|
|
431
364
|
if (base64Index !== -1) {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
365
|
+
if (!format) {
|
|
366
|
+
const mimeMatch = normalizedBase64.match(/data:image\/(\w+);/);
|
|
367
|
+
if (mimeMatch && mimeMatch[1]) {
|
|
368
|
+
normalizedFormat = mimeMatch[1] === "jpeg" ? "jpg" : mimeMatch[1];
|
|
369
|
+
}
|
|
436
370
|
}
|
|
437
|
-
|
|
438
|
-
base64Data = base64Data.substring(base64Index + 7);
|
|
371
|
+
normalizedBase64 = normalizedBase64.substring(base64Index + 7);
|
|
439
372
|
}
|
|
440
373
|
}
|
|
441
|
-
|
|
374
|
+
this.sendWebSocketCommand({
|
|
442
375
|
cmd_type: "loadImageFromBase64",
|
|
443
|
-
base64Data:
|
|
444
|
-
format:
|
|
445
|
-
};
|
|
446
|
-
this.sendWebSocketCommand(cmdObj);
|
|
376
|
+
base64Data: normalizedBase64,
|
|
377
|
+
format: normalizedFormat
|
|
378
|
+
});
|
|
447
379
|
}
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* 发送指令旋转某一页图像到托盘服务
|
|
451
|
-
* @param {number} index - 图像索引
|
|
452
|
-
* @param {number} angle - 旋转角度
|
|
453
|
-
*/
|
|
454
380
|
rotateImage(index, angle) {
|
|
455
|
-
|
|
381
|
+
this.sendWebSocketCommand({
|
|
456
382
|
cmd_type: "rotateImage",
|
|
457
383
|
index: index,
|
|
458
384
|
angle: angle
|
|
459
|
-
};
|
|
460
|
-
this.sendWebSocketCommand(cmdObj);
|
|
385
|
+
});
|
|
461
386
|
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* 发送指令获取某一页图像的宽度到托盘服务
|
|
465
|
-
* @param {number} index - 图像索引
|
|
466
|
-
*/
|
|
467
387
|
getImageSize(index) {
|
|
468
|
-
|
|
388
|
+
this.sendWebSocketCommand({
|
|
469
389
|
cmd_type: "getImageSize",
|
|
470
390
|
index: index
|
|
471
|
-
};
|
|
472
|
-
this.sendWebSocketCommand(cmdObj);
|
|
391
|
+
});
|
|
473
392
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
* 发送指令删除某一页图像到托盘服务
|
|
477
|
-
* @param {number} index - 图像索引
|
|
478
|
-
*/
|
|
479
|
-
deleteImageByIndex(index) {
|
|
480
|
-
const cmdObj = {
|
|
393
|
+
deleteImageByIndex(index, imageId) {
|
|
394
|
+
const command = {
|
|
481
395
|
cmd_type: "deleteImageByIndex",
|
|
482
396
|
index: index
|
|
483
397
|
};
|
|
484
|
-
|
|
398
|
+
if (typeof imageId === "string" && imageId.trim()) {
|
|
399
|
+
command.imageId = imageId.trim();
|
|
400
|
+
}
|
|
401
|
+
this.sendWebSocketCommand(command);
|
|
402
|
+
}
|
|
403
|
+
moveImage(oldIndex, newIndex) {
|
|
404
|
+
this.sendWebSocketCommand({
|
|
405
|
+
cmd_type: "moveImage",
|
|
406
|
+
oldIndex: oldIndex,
|
|
407
|
+
newIndex: newIndex
|
|
408
|
+
});
|
|
485
409
|
}
|
|
486
|
-
|
|
487
|
-
/**
|
|
488
|
-
* 以pdf格式上传全部图像到服务器端
|
|
489
|
-
* @param {string} url - 上传URL
|
|
490
|
-
* @param {string} id - 标识ID
|
|
491
|
-
* @param {string} desc - 描述信息
|
|
492
|
-
*/
|
|
493
410
|
uploadAllImageAsPdfToUrl(url, id, desc) {
|
|
494
|
-
|
|
411
|
+
this.sendWebSocketCommand({
|
|
495
412
|
cmd_type: "uploadAllImageAsPdfToUrl",
|
|
496
413
|
url: url,
|
|
497
414
|
id: id,
|
|
498
415
|
desc: desc
|
|
499
|
-
};
|
|
500
|
-
this.sendWebSocketCommand(cmdObj);
|
|
416
|
+
});
|
|
501
417
|
}
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* 以tiff格式上传全部图像到服务器端
|
|
505
|
-
* @param {string} url - 上传URL
|
|
506
|
-
* @param {string} id - 标识ID
|
|
507
|
-
* @param {string} desc - 描述信息
|
|
508
|
-
*/
|
|
509
418
|
uploadAllImageAsTiffToUrl(url, id, desc) {
|
|
510
|
-
|
|
419
|
+
this.sendWebSocketCommand({
|
|
511
420
|
cmd_type: "uploadAllImageAsTiffToUrl",
|
|
512
421
|
url: url,
|
|
513
422
|
id: id,
|
|
514
423
|
desc: desc
|
|
515
|
-
};
|
|
516
|
-
this.sendWebSocketCommand(cmdObj);
|
|
424
|
+
});
|
|
517
425
|
}
|
|
518
|
-
|
|
519
|
-
/**
|
|
520
|
-
* 以jpg格式上传某一页图像到服务器端
|
|
521
|
-
* @param {string} url - 上传URL
|
|
522
|
-
* @param {string} id - 标识ID
|
|
523
|
-
* @param {string} desc - 描述信息
|
|
524
|
-
* @param {number} index - 图像索引
|
|
525
|
-
*/
|
|
526
426
|
uploadJpgImageByIndex(url, id, desc, index) {
|
|
527
|
-
|
|
427
|
+
this.sendWebSocketCommand({
|
|
528
428
|
cmd_type: "uploadJpgImageByIndex",
|
|
529
429
|
index: index,
|
|
530
430
|
url: url,
|
|
531
431
|
id: id,
|
|
532
432
|
desc: desc
|
|
533
|
-
};
|
|
534
|
-
this.sendWebSocketCommand(cmdObj);
|
|
433
|
+
});
|
|
535
434
|
}
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* 全部图像保存到客户端本地文件
|
|
539
|
-
* @param {string} filename - 文件名
|
|
540
|
-
*/
|
|
541
435
|
saveAllImageToLocal(filename) {
|
|
542
|
-
|
|
436
|
+
this.sendWebSocketCommand({
|
|
543
437
|
cmd_type: "saveAllImageToLocal",
|
|
544
438
|
filename: filename
|
|
545
|
-
};
|
|
546
|
-
this.sendWebSocketCommand(cmdObj);
|
|
439
|
+
});
|
|
547
440
|
}
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* 从客户端本地读取图像,通过打开文件对话框选择图像文件
|
|
551
|
-
*/
|
|
552
441
|
openClientLocalfile() {
|
|
553
|
-
|
|
442
|
+
this.sendWebSocketCommand({
|
|
554
443
|
cmd_type: "openClientLocalfile"
|
|
555
|
-
};
|
|
556
|
-
this.sendWebSocketCommand(cmdObj);
|
|
444
|
+
});
|
|
557
445
|
}
|
|
558
|
-
|
|
559
|
-
/**
|
|
560
|
-
* ftp上传全部图像文件到服务器端
|
|
561
|
-
* @param {string} serverIp - 服务器IP
|
|
562
|
-
* @param {number} port - 端口
|
|
563
|
-
* @param {string} username - 用户名
|
|
564
|
-
* @param {string} password - 密码
|
|
565
|
-
* @param {string} serverPath - 服务器路径
|
|
566
|
-
* @param {string} filename - 文件名
|
|
567
|
-
*/
|
|
568
446
|
ftpUploadAllImage(serverIp, port, username, password, serverPath, filename) {
|
|
569
|
-
|
|
447
|
+
this.sendWebSocketCommand({
|
|
570
448
|
cmd_type: "ftpUploadAllImage",
|
|
571
449
|
serverIp: serverIp,
|
|
572
450
|
port: port,
|
|
@@ -574,114 +452,66 @@ class ScanOnWeb {
|
|
|
574
452
|
password: password,
|
|
575
453
|
serverPath: serverPath,
|
|
576
454
|
filename: filename
|
|
577
|
-
};
|
|
578
|
-
this.sendWebSocketCommand(cmdObj);
|
|
455
|
+
});
|
|
579
456
|
}
|
|
580
|
-
|
|
581
|
-
/**
|
|
582
|
-
* 设置上传按钮是否可见
|
|
583
|
-
* @param {boolean} visible - 是否可见
|
|
584
|
-
*/
|
|
585
457
|
setUploadButtonVisible(visible) {
|
|
586
|
-
|
|
458
|
+
this.sendWebSocketCommand({
|
|
587
459
|
cmd_type: "setUploadButtonVisible",
|
|
588
460
|
visible: visible
|
|
589
|
-
};
|
|
590
|
-
this.sendWebSocketCommand(cmdObj);
|
|
461
|
+
});
|
|
591
462
|
}
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* 设置焦点
|
|
595
|
-
*/
|
|
596
463
|
setFocus() {
|
|
597
|
-
|
|
464
|
+
this.sendWebSocketCommand({
|
|
598
465
|
cmd_type: "focus"
|
|
599
|
-
};
|
|
600
|
-
this.sendWebSocketCommand(cmdObj);
|
|
466
|
+
});
|
|
601
467
|
}
|
|
602
|
-
|
|
603
|
-
/**
|
|
604
|
-
* 隐藏窗口
|
|
605
|
-
*/
|
|
606
468
|
hidden() {
|
|
607
|
-
|
|
469
|
+
this.sendWebSocketCommand({
|
|
608
470
|
cmd_type: "hidden"
|
|
609
|
-
};
|
|
610
|
-
this.sendWebSocketCommand(cmdObj);
|
|
471
|
+
});
|
|
611
472
|
}
|
|
612
|
-
|
|
613
|
-
/**
|
|
614
|
-
* 关闭websocket连接
|
|
615
|
-
*/
|
|
616
473
|
closeWebSocket() {
|
|
617
474
|
this.h5socket.close();
|
|
618
475
|
}
|
|
619
|
-
|
|
620
|
-
/**
|
|
621
|
-
* 批量从Base64数据加载多个图像
|
|
622
|
-
* @param {Array} base64Images - Base64图像数组,每个元素为 {data: 'base64字符串', format: '格式'}
|
|
623
|
-
*/
|
|
624
476
|
loadMultipleImagesFromBase64(base64Images) {
|
|
625
477
|
if (!Array.isArray(base64Images) || base64Images.length === 0) {
|
|
626
|
-
console.error(
|
|
478
|
+
console.error("loadMultipleImagesFromBase64: 参数必须是非空数组");
|
|
627
479
|
return;
|
|
628
480
|
}
|
|
629
|
-
|
|
630
|
-
// 逐个加载图像
|
|
631
481
|
base64Images.forEach((image, index) => {
|
|
632
482
|
setTimeout(() => {
|
|
633
|
-
this.loadImageFromBase64(image.data, image.format ||
|
|
634
|
-
}, index * 100);
|
|
483
|
+
this.loadImageFromBase64(image.data, image.format || "jpg");
|
|
484
|
+
}, index * 100);
|
|
635
485
|
});
|
|
636
486
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
* @param {HTMLCanvasElement} canvas - Canvas元素
|
|
641
|
-
* @param {string} [format='jpg'] - 图像格式
|
|
642
|
-
* @param {number} [quality=0.9] - 图像质量(0-1之间,仅对jpg格式有效)
|
|
643
|
-
*/
|
|
644
|
-
loadImageFromCanvas(canvas, format = 'jpg', quality = 0.9) {
|
|
487
|
+
loadImageFromCanvas(canvas, format, quality) {
|
|
488
|
+
const normalizedFormat = format || "jpg";
|
|
489
|
+
const normalizedQuality = typeof quality === "number" ? quality : 0.9;
|
|
645
490
|
if (!canvas || !(canvas instanceof HTMLCanvasElement)) {
|
|
646
|
-
console.error(
|
|
491
|
+
console.error("loadImageFromCanvas: 参数必须是有效的Canvas元素");
|
|
647
492
|
return;
|
|
648
493
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
// 提取Base64数据部分
|
|
655
|
-
const base64Data = dataUrl.split(',')[1];
|
|
656
|
-
|
|
657
|
-
// 调用Base64加载方法
|
|
658
|
-
this.loadImageFromBase64(base64Data, format);
|
|
494
|
+
const mimeType = normalizedFormat === "jpg" ? "image/jpeg" : "image/" + normalizedFormat;
|
|
495
|
+
const dataUrl = canvas.toDataURL(mimeType, normalizedQuality);
|
|
496
|
+
const base64Data = dataUrl.split(",")[1];
|
|
497
|
+
this.loadImageFromBase64(base64Data, normalizedFormat);
|
|
659
498
|
}
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* 从文件输入元素加载图像
|
|
663
|
-
* @param {HTMLInputElement} fileInput - 文件输入元素
|
|
664
|
-
*/
|
|
665
499
|
loadImageFromFileInput(fileInput) {
|
|
666
500
|
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
|
|
667
|
-
console.error(
|
|
501
|
+
console.error("loadImageFromFileInput: 没有选择文件");
|
|
668
502
|
return;
|
|
669
503
|
}
|
|
670
504
|
const files = Array.from(fileInput.files);
|
|
671
505
|
files.forEach((file, index) => {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
console.warn(`跳过非图像文件: ${file.name}`);
|
|
506
|
+
if (!file.type.startsWith("image/")) {
|
|
507
|
+
console.warn("跳过非图像文件: " + file.name);
|
|
675
508
|
return;
|
|
676
509
|
}
|
|
677
510
|
const reader = new FileReader();
|
|
678
511
|
reader.onload = e => {
|
|
679
512
|
const dataUrl = e.target.result;
|
|
680
|
-
|
|
681
|
-
const
|
|
682
|
-
const format = extension === 'jpeg' ? 'jpg' : extension;
|
|
683
|
-
|
|
684
|
-
// 延迟加载,避免同时处理过多文件
|
|
513
|
+
const extension = file.name.split(".").pop().toLowerCase();
|
|
514
|
+
const format = extension === "jpeg" ? "jpg" : extension;
|
|
685
515
|
setTimeout(() => {
|
|
686
516
|
this.loadImageFromBase64(dataUrl, format);
|
|
687
517
|
}, index * 100);
|
|
@@ -690,13 +520,9 @@ class ScanOnWeb {
|
|
|
690
520
|
});
|
|
691
521
|
}
|
|
692
522
|
}
|
|
693
|
-
|
|
694
|
-
// CommonJS 兼容性导出
|
|
695
523
|
if (typeof module !== "undefined" && module.exports) {
|
|
696
524
|
module.exports = ScanOnWeb;
|
|
697
525
|
}
|
|
698
|
-
|
|
699
|
-
// UMD 兼容性导出
|
|
700
526
|
if (typeof window !== "undefined") {
|
|
701
527
|
window.ScanOnWeb = ScanOnWeb;
|
|
702
528
|
}
|