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