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