scanonweb 1.0.1 → 1.0.3
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 +9 -0
- package/dist/scanonweb.cjs.js +145 -5
- package/dist/scanonweb.esm.js +145 -5
- package/dist/scanonweb.umd.js +145 -5
- package/dist/scanonweb.umd.min.js +3 -3
- package/package.json +1 -1
- package/src/index.d.ts +7 -0
- package/src/index.js +146 -2
- package/dist/index.d.ts +0 -266
package/README.md
CHANGED
|
@@ -148,6 +148,7 @@ scanner.scaner_work_config = {
|
|
|
148
148
|
- `getImageById(index)` - 获取指定索引的图像
|
|
149
149
|
- `rotateImage(index, angle)` - 旋转图像
|
|
150
150
|
- `deleteImageByIndex(index)` - 删除指定图像
|
|
151
|
+
- `moveImage(oldIndex, newIndex)` - 调整图像顺序(将 oldIndex 移动到 newIndex)
|
|
151
152
|
|
|
152
153
|
#### 上传功能
|
|
153
154
|
- `uploadAllImageAsPdfToUrl(url, id, desc)` - 以PDF格式上传所有图像
|
|
@@ -196,6 +197,14 @@ MIT License
|
|
|
196
197
|
|
|
197
198
|
## 更新日志
|
|
198
199
|
|
|
200
|
+
### 1.0.3
|
|
201
|
+
- 添加了支持前端直接调整扫描结果图像顺序的能力,前端可以通过moveImage函数调整结果图像顺序
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
### 1.0.2
|
|
205
|
+
- 添加了对加载base64格式图像的支持
|
|
206
|
+
- 远程加载图像除了支持pdf和tiff格式,现在也支持加载jpg、png等常见格式的图像
|
|
207
|
+
|
|
199
208
|
### 1.0.1
|
|
200
209
|
- 初始版本发布
|
|
201
210
|
- 支持基本扫描功能
|
package/dist/scanonweb.cjs.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* scanonweb v1.0.
|
|
2
|
+
* scanonweb v1.0.3
|
|
3
3
|
* ScanOnWeb - 扫描控件 JavaScript SDK,用于与本地扫描服务程序通信
|
|
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
|
'use strict';
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
/**
|
|
12
12
|
* ScanOnWeb - 扫描控件 JavaScript SDK
|
|
13
13
|
* https://www.brainysoft.cn 扫描控件官方网站,如需更多文档帮助请访问官网
|
|
14
|
-
* @version 1.0.
|
|
14
|
+
* @version 1.0.3
|
|
15
15
|
* @author BrainySoft
|
|
16
16
|
* @license MIT
|
|
17
17
|
*/
|
|
@@ -204,6 +204,15 @@ class ScanOnWeb {
|
|
|
204
204
|
}
|
|
205
205
|
break;
|
|
206
206
|
}
|
|
207
|
+
case "loadImageFromBase64":
|
|
208
|
+
{
|
|
209
|
+
// 从Base64数据加载图片
|
|
210
|
+
this.imageCount = msg.imageCount;
|
|
211
|
+
if (this.isCallbackExist(this.onLoadImageFromBase64Event)) {
|
|
212
|
+
this.onLoadImageFromBase64Event(msg);
|
|
213
|
+
}
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
207
216
|
case "rotateImage":
|
|
208
217
|
{
|
|
209
218
|
// 旋转图片
|
|
@@ -385,12 +394,56 @@ class ScanOnWeb {
|
|
|
385
394
|
|
|
386
395
|
/**
|
|
387
396
|
* 发送指令远程加载服务器端的多页图像到托盘服务
|
|
397
|
+
* 支持PDF、TIFF以及常见图像格式(JPG、PNG、BMP等)
|
|
388
398
|
* @param {string} url - 图像URL
|
|
399
|
+
* @param {string} [type] - 可选,指定文件类型:'pdf'、'tiff'、'image',如果不指定则根据URL扩展名自动判断
|
|
389
400
|
*/
|
|
390
|
-
loadImageFromUrl(url) {
|
|
401
|
+
loadImageFromUrl(url, type) {
|
|
402
|
+
// 如果没有指定类型,则根据URL扩展名自动判断
|
|
403
|
+
if (!type) {
|
|
404
|
+
const extension = url.split('.').pop().toLowerCase();
|
|
405
|
+
if (extension === 'pdf') {
|
|
406
|
+
type = 'pdf';
|
|
407
|
+
} else if (extension === 'tiff' || extension === 'tif') {
|
|
408
|
+
type = 'tiff';
|
|
409
|
+
} else if (['jpg', 'jpeg', 'png', 'bmp', 'gif', 'webp'].includes(extension)) {
|
|
410
|
+
type = 'image';
|
|
411
|
+
} else {
|
|
412
|
+
// 默认当作普通图像处理
|
|
413
|
+
type = 'image';
|
|
414
|
+
}
|
|
415
|
+
}
|
|
391
416
|
const cmdObj = {
|
|
392
417
|
cmd_type: "loadImageFromUrl",
|
|
393
|
-
url: url
|
|
418
|
+
url: url,
|
|
419
|
+
type: type
|
|
420
|
+
};
|
|
421
|
+
this.sendWebSocketCommand(cmdObj);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* 发送指令从Base64编码数据加载图像到托盘服务
|
|
426
|
+
* @param {string} base64Data - Base64编码的图像数据(不包含data:image/xxx;base64,前缀)
|
|
427
|
+
* @param {string} [format='jpg'] - 图像格式,如:'jpg'、'png'、'bmp'等,默认为'jpg'
|
|
428
|
+
*/
|
|
429
|
+
loadImageFromBase64(base64Data, format = 'jpg') {
|
|
430
|
+
// 如果base64数据包含data URL前缀,则去除它
|
|
431
|
+
if (base64Data.startsWith('data:')) {
|
|
432
|
+
const base64Index = base64Data.indexOf('base64,');
|
|
433
|
+
if (base64Index !== -1) {
|
|
434
|
+
// 尝试从data URL中提取格式信息
|
|
435
|
+
const mimeMatch = base64Data.match(/data:image\/(\w+);/);
|
|
436
|
+
if (mimeMatch && mimeMatch[1] && !format) {
|
|
437
|
+
format = mimeMatch[1] === 'jpeg' ? 'jpg' : mimeMatch[1];
|
|
438
|
+
}
|
|
439
|
+
// 提取纯Base64数据
|
|
440
|
+
base64Data = base64Data.substring(base64Index + 7);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
const cmdObj = {
|
|
444
|
+
cmd_type: "loadImageFromBase64",
|
|
445
|
+
base64Data: base64Data,
|
|
446
|
+
format: format
|
|
394
447
|
};
|
|
395
448
|
this.sendWebSocketCommand(cmdObj);
|
|
396
449
|
}
|
|
@@ -433,6 +486,20 @@ class ScanOnWeb {
|
|
|
433
486
|
this.sendWebSocketCommand(cmdObj);
|
|
434
487
|
}
|
|
435
488
|
|
|
489
|
+
/**
|
|
490
|
+
* 前端调整扫描结果图像顺序
|
|
491
|
+
* @param {number} oldIndex - 原图像索引
|
|
492
|
+
* @param {number} newIndex - 目标图像索引
|
|
493
|
+
*/
|
|
494
|
+
moveImage(oldIndex, newIndex) {
|
|
495
|
+
const cmdObj = {
|
|
496
|
+
cmd_type: "moveImage",
|
|
497
|
+
oldIndex: oldIndex,
|
|
498
|
+
newIndex: newIndex
|
|
499
|
+
};
|
|
500
|
+
this.sendWebSocketCommand(cmdObj);
|
|
501
|
+
}
|
|
502
|
+
|
|
436
503
|
/**
|
|
437
504
|
* 以pdf格式上传全部图像到服务器端
|
|
438
505
|
* @param {string} url - 上传URL
|
|
@@ -565,6 +632,79 @@ class ScanOnWeb {
|
|
|
565
632
|
closeWebSocket() {
|
|
566
633
|
this.h5socket.close();
|
|
567
634
|
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* 批量从Base64数据加载多个图像
|
|
638
|
+
* @param {Array} base64Images - Base64图像数组,每个元素为 {data: 'base64字符串', format: '格式'}
|
|
639
|
+
*/
|
|
640
|
+
loadMultipleImagesFromBase64(base64Images) {
|
|
641
|
+
if (!Array.isArray(base64Images) || base64Images.length === 0) {
|
|
642
|
+
console.error('loadMultipleImagesFromBase64: 参数必须是非空数组');
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// 逐个加载图像
|
|
647
|
+
base64Images.forEach((image, index) => {
|
|
648
|
+
setTimeout(() => {
|
|
649
|
+
this.loadImageFromBase64(image.data, image.format || 'jpg');
|
|
650
|
+
}, index * 100); // 每个图像间隔100ms,避免同时发送过多数据
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* 从Canvas元素加载图像
|
|
656
|
+
* @param {HTMLCanvasElement} canvas - Canvas元素
|
|
657
|
+
* @param {string} [format='jpg'] - 图像格式
|
|
658
|
+
* @param {number} [quality=0.9] - 图像质量(0-1之间,仅对jpg格式有效)
|
|
659
|
+
*/
|
|
660
|
+
loadImageFromCanvas(canvas, format = 'jpg', quality = 0.9) {
|
|
661
|
+
if (!canvas || !(canvas instanceof HTMLCanvasElement)) {
|
|
662
|
+
console.error('loadImageFromCanvas: 参数必须是有效的Canvas元素');
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// 将Canvas转换为Base64
|
|
667
|
+
const mimeType = format === 'jpg' ? 'image/jpeg' : `image/${format}`;
|
|
668
|
+
const dataUrl = canvas.toDataURL(mimeType, quality);
|
|
669
|
+
|
|
670
|
+
// 提取Base64数据部分
|
|
671
|
+
const base64Data = dataUrl.split(',')[1];
|
|
672
|
+
|
|
673
|
+
// 调用Base64加载方法
|
|
674
|
+
this.loadImageFromBase64(base64Data, format);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* 从文件输入元素加载图像
|
|
679
|
+
* @param {HTMLInputElement} fileInput - 文件输入元素
|
|
680
|
+
*/
|
|
681
|
+
loadImageFromFileInput(fileInput) {
|
|
682
|
+
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
|
|
683
|
+
console.error('loadImageFromFileInput: 没有选择文件');
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
const files = Array.from(fileInput.files);
|
|
687
|
+
files.forEach((file, index) => {
|
|
688
|
+
// 检查是否为图像文件
|
|
689
|
+
if (!file.type.startsWith('image/')) {
|
|
690
|
+
console.warn(`跳过非图像文件: ${file.name}`);
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
const reader = new FileReader();
|
|
694
|
+
reader.onload = e => {
|
|
695
|
+
const dataUrl = e.target.result;
|
|
696
|
+
// 获取文件扩展名
|
|
697
|
+
const extension = file.name.split('.').pop().toLowerCase();
|
|
698
|
+
const format = extension === 'jpeg' ? 'jpg' : extension;
|
|
699
|
+
|
|
700
|
+
// 延迟加载,避免同时处理过多文件
|
|
701
|
+
setTimeout(() => {
|
|
702
|
+
this.loadImageFromBase64(dataUrl, format);
|
|
703
|
+
}, index * 100);
|
|
704
|
+
};
|
|
705
|
+
reader.readAsDataURL(file);
|
|
706
|
+
});
|
|
707
|
+
}
|
|
568
708
|
}
|
|
569
709
|
|
|
570
710
|
// CommonJS 兼容性导出
|
package/dist/scanonweb.esm.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* scanonweb v1.0.
|
|
2
|
+
* scanonweb v1.0.3
|
|
3
3
|
* ScanOnWeb - 扫描控件 JavaScript SDK,用于与本地扫描服务程序通信
|
|
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
10
|
* ScanOnWeb - 扫描控件 JavaScript SDK
|
|
11
11
|
* https://www.brainysoft.cn 扫描控件官方网站,如需更多文档帮助请访问官网
|
|
12
|
-
* @version 1.0.
|
|
12
|
+
* @version 1.0.3
|
|
13
13
|
* @author BrainySoft
|
|
14
14
|
* @license MIT
|
|
15
15
|
*/
|
|
@@ -202,6 +202,15 @@ class ScanOnWeb {
|
|
|
202
202
|
}
|
|
203
203
|
break;
|
|
204
204
|
}
|
|
205
|
+
case "loadImageFromBase64":
|
|
206
|
+
{
|
|
207
|
+
// 从Base64数据加载图片
|
|
208
|
+
this.imageCount = msg.imageCount;
|
|
209
|
+
if (this.isCallbackExist(this.onLoadImageFromBase64Event)) {
|
|
210
|
+
this.onLoadImageFromBase64Event(msg);
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
205
214
|
case "rotateImage":
|
|
206
215
|
{
|
|
207
216
|
// 旋转图片
|
|
@@ -383,12 +392,56 @@ class ScanOnWeb {
|
|
|
383
392
|
|
|
384
393
|
/**
|
|
385
394
|
* 发送指令远程加载服务器端的多页图像到托盘服务
|
|
395
|
+
* 支持PDF、TIFF以及常见图像格式(JPG、PNG、BMP等)
|
|
386
396
|
* @param {string} url - 图像URL
|
|
397
|
+
* @param {string} [type] - 可选,指定文件类型:'pdf'、'tiff'、'image',如果不指定则根据URL扩展名自动判断
|
|
387
398
|
*/
|
|
388
|
-
loadImageFromUrl(url) {
|
|
399
|
+
loadImageFromUrl(url, type) {
|
|
400
|
+
// 如果没有指定类型,则根据URL扩展名自动判断
|
|
401
|
+
if (!type) {
|
|
402
|
+
const extension = url.split('.').pop().toLowerCase();
|
|
403
|
+
if (extension === 'pdf') {
|
|
404
|
+
type = 'pdf';
|
|
405
|
+
} else if (extension === 'tiff' || extension === 'tif') {
|
|
406
|
+
type = 'tiff';
|
|
407
|
+
} else if (['jpg', 'jpeg', 'png', 'bmp', 'gif', 'webp'].includes(extension)) {
|
|
408
|
+
type = 'image';
|
|
409
|
+
} else {
|
|
410
|
+
// 默认当作普通图像处理
|
|
411
|
+
type = 'image';
|
|
412
|
+
}
|
|
413
|
+
}
|
|
389
414
|
const cmdObj = {
|
|
390
415
|
cmd_type: "loadImageFromUrl",
|
|
391
|
-
url: url
|
|
416
|
+
url: url,
|
|
417
|
+
type: type
|
|
418
|
+
};
|
|
419
|
+
this.sendWebSocketCommand(cmdObj);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* 发送指令从Base64编码数据加载图像到托盘服务
|
|
424
|
+
* @param {string} base64Data - Base64编码的图像数据(不包含data:image/xxx;base64,前缀)
|
|
425
|
+
* @param {string} [format='jpg'] - 图像格式,如:'jpg'、'png'、'bmp'等,默认为'jpg'
|
|
426
|
+
*/
|
|
427
|
+
loadImageFromBase64(base64Data, format = 'jpg') {
|
|
428
|
+
// 如果base64数据包含data URL前缀,则去除它
|
|
429
|
+
if (base64Data.startsWith('data:')) {
|
|
430
|
+
const base64Index = base64Data.indexOf('base64,');
|
|
431
|
+
if (base64Index !== -1) {
|
|
432
|
+
// 尝试从data URL中提取格式信息
|
|
433
|
+
const mimeMatch = base64Data.match(/data:image\/(\w+);/);
|
|
434
|
+
if (mimeMatch && mimeMatch[1] && !format) {
|
|
435
|
+
format = mimeMatch[1] === 'jpeg' ? 'jpg' : mimeMatch[1];
|
|
436
|
+
}
|
|
437
|
+
// 提取纯Base64数据
|
|
438
|
+
base64Data = base64Data.substring(base64Index + 7);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const cmdObj = {
|
|
442
|
+
cmd_type: "loadImageFromBase64",
|
|
443
|
+
base64Data: base64Data,
|
|
444
|
+
format: format
|
|
392
445
|
};
|
|
393
446
|
this.sendWebSocketCommand(cmdObj);
|
|
394
447
|
}
|
|
@@ -431,6 +484,20 @@ class ScanOnWeb {
|
|
|
431
484
|
this.sendWebSocketCommand(cmdObj);
|
|
432
485
|
}
|
|
433
486
|
|
|
487
|
+
/**
|
|
488
|
+
* 前端调整扫描结果图像顺序
|
|
489
|
+
* @param {number} oldIndex - 原图像索引
|
|
490
|
+
* @param {number} newIndex - 目标图像索引
|
|
491
|
+
*/
|
|
492
|
+
moveImage(oldIndex, newIndex) {
|
|
493
|
+
const cmdObj = {
|
|
494
|
+
cmd_type: "moveImage",
|
|
495
|
+
oldIndex: oldIndex,
|
|
496
|
+
newIndex: newIndex
|
|
497
|
+
};
|
|
498
|
+
this.sendWebSocketCommand(cmdObj);
|
|
499
|
+
}
|
|
500
|
+
|
|
434
501
|
/**
|
|
435
502
|
* 以pdf格式上传全部图像到服务器端
|
|
436
503
|
* @param {string} url - 上传URL
|
|
@@ -563,6 +630,79 @@ class ScanOnWeb {
|
|
|
563
630
|
closeWebSocket() {
|
|
564
631
|
this.h5socket.close();
|
|
565
632
|
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* 批量从Base64数据加载多个图像
|
|
636
|
+
* @param {Array} base64Images - Base64图像数组,每个元素为 {data: 'base64字符串', format: '格式'}
|
|
637
|
+
*/
|
|
638
|
+
loadMultipleImagesFromBase64(base64Images) {
|
|
639
|
+
if (!Array.isArray(base64Images) || base64Images.length === 0) {
|
|
640
|
+
console.error('loadMultipleImagesFromBase64: 参数必须是非空数组');
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// 逐个加载图像
|
|
645
|
+
base64Images.forEach((image, index) => {
|
|
646
|
+
setTimeout(() => {
|
|
647
|
+
this.loadImageFromBase64(image.data, image.format || 'jpg');
|
|
648
|
+
}, index * 100); // 每个图像间隔100ms,避免同时发送过多数据
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* 从Canvas元素加载图像
|
|
654
|
+
* @param {HTMLCanvasElement} canvas - Canvas元素
|
|
655
|
+
* @param {string} [format='jpg'] - 图像格式
|
|
656
|
+
* @param {number} [quality=0.9] - 图像质量(0-1之间,仅对jpg格式有效)
|
|
657
|
+
*/
|
|
658
|
+
loadImageFromCanvas(canvas, format = 'jpg', quality = 0.9) {
|
|
659
|
+
if (!canvas || !(canvas instanceof HTMLCanvasElement)) {
|
|
660
|
+
console.error('loadImageFromCanvas: 参数必须是有效的Canvas元素');
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// 将Canvas转换为Base64
|
|
665
|
+
const mimeType = format === 'jpg' ? 'image/jpeg' : `image/${format}`;
|
|
666
|
+
const dataUrl = canvas.toDataURL(mimeType, quality);
|
|
667
|
+
|
|
668
|
+
// 提取Base64数据部分
|
|
669
|
+
const base64Data = dataUrl.split(',')[1];
|
|
670
|
+
|
|
671
|
+
// 调用Base64加载方法
|
|
672
|
+
this.loadImageFromBase64(base64Data, format);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* 从文件输入元素加载图像
|
|
677
|
+
* @param {HTMLInputElement} fileInput - 文件输入元素
|
|
678
|
+
*/
|
|
679
|
+
loadImageFromFileInput(fileInput) {
|
|
680
|
+
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
|
|
681
|
+
console.error('loadImageFromFileInput: 没有选择文件');
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
const files = Array.from(fileInput.files);
|
|
685
|
+
files.forEach((file, index) => {
|
|
686
|
+
// 检查是否为图像文件
|
|
687
|
+
if (!file.type.startsWith('image/')) {
|
|
688
|
+
console.warn(`跳过非图像文件: ${file.name}`);
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
const reader = new FileReader();
|
|
692
|
+
reader.onload = e => {
|
|
693
|
+
const dataUrl = e.target.result;
|
|
694
|
+
// 获取文件扩展名
|
|
695
|
+
const extension = file.name.split('.').pop().toLowerCase();
|
|
696
|
+
const format = extension === 'jpeg' ? 'jpg' : extension;
|
|
697
|
+
|
|
698
|
+
// 延迟加载,避免同时处理过多文件
|
|
699
|
+
setTimeout(() => {
|
|
700
|
+
this.loadImageFromBase64(dataUrl, format);
|
|
701
|
+
}, index * 100);
|
|
702
|
+
};
|
|
703
|
+
reader.readAsDataURL(file);
|
|
704
|
+
});
|
|
705
|
+
}
|
|
566
706
|
}
|
|
567
707
|
|
|
568
708
|
// CommonJS 兼容性导出
|
package/dist/scanonweb.umd.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* scanonweb v1.0.
|
|
2
|
+
* scanonweb v1.0.3
|
|
3
3
|
* ScanOnWeb - 扫描控件 JavaScript SDK,用于与本地扫描服务程序通信
|
|
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
|
(function (global, factory) {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
/**
|
|
16
16
|
* ScanOnWeb - 扫描控件 JavaScript SDK
|
|
17
17
|
* https://www.brainysoft.cn 扫描控件官方网站,如需更多文档帮助请访问官网
|
|
18
|
-
* @version 1.0.
|
|
18
|
+
* @version 1.0.3
|
|
19
19
|
* @author BrainySoft
|
|
20
20
|
* @license MIT
|
|
21
21
|
*/
|
|
@@ -208,6 +208,15 @@
|
|
|
208
208
|
}
|
|
209
209
|
break;
|
|
210
210
|
}
|
|
211
|
+
case "loadImageFromBase64":
|
|
212
|
+
{
|
|
213
|
+
// 从Base64数据加载图片
|
|
214
|
+
this.imageCount = msg.imageCount;
|
|
215
|
+
if (this.isCallbackExist(this.onLoadImageFromBase64Event)) {
|
|
216
|
+
this.onLoadImageFromBase64Event(msg);
|
|
217
|
+
}
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
211
220
|
case "rotateImage":
|
|
212
221
|
{
|
|
213
222
|
// 旋转图片
|
|
@@ -389,12 +398,56 @@
|
|
|
389
398
|
|
|
390
399
|
/**
|
|
391
400
|
* 发送指令远程加载服务器端的多页图像到托盘服务
|
|
401
|
+
* 支持PDF、TIFF以及常见图像格式(JPG、PNG、BMP等)
|
|
392
402
|
* @param {string} url - 图像URL
|
|
403
|
+
* @param {string} [type] - 可选,指定文件类型:'pdf'、'tiff'、'image',如果不指定则根据URL扩展名自动判断
|
|
393
404
|
*/
|
|
394
|
-
loadImageFromUrl(url) {
|
|
405
|
+
loadImageFromUrl(url, type) {
|
|
406
|
+
// 如果没有指定类型,则根据URL扩展名自动判断
|
|
407
|
+
if (!type) {
|
|
408
|
+
const extension = url.split('.').pop().toLowerCase();
|
|
409
|
+
if (extension === 'pdf') {
|
|
410
|
+
type = 'pdf';
|
|
411
|
+
} else if (extension === 'tiff' || extension === 'tif') {
|
|
412
|
+
type = 'tiff';
|
|
413
|
+
} else if (['jpg', 'jpeg', 'png', 'bmp', 'gif', 'webp'].includes(extension)) {
|
|
414
|
+
type = 'image';
|
|
415
|
+
} else {
|
|
416
|
+
// 默认当作普通图像处理
|
|
417
|
+
type = 'image';
|
|
418
|
+
}
|
|
419
|
+
}
|
|
395
420
|
const cmdObj = {
|
|
396
421
|
cmd_type: "loadImageFromUrl",
|
|
397
|
-
url: url
|
|
422
|
+
url: url,
|
|
423
|
+
type: type
|
|
424
|
+
};
|
|
425
|
+
this.sendWebSocketCommand(cmdObj);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* 发送指令从Base64编码数据加载图像到托盘服务
|
|
430
|
+
* @param {string} base64Data - Base64编码的图像数据(不包含data:image/xxx;base64,前缀)
|
|
431
|
+
* @param {string} [format='jpg'] - 图像格式,如:'jpg'、'png'、'bmp'等,默认为'jpg'
|
|
432
|
+
*/
|
|
433
|
+
loadImageFromBase64(base64Data, format = 'jpg') {
|
|
434
|
+
// 如果base64数据包含data URL前缀,则去除它
|
|
435
|
+
if (base64Data.startsWith('data:')) {
|
|
436
|
+
const base64Index = base64Data.indexOf('base64,');
|
|
437
|
+
if (base64Index !== -1) {
|
|
438
|
+
// 尝试从data URL中提取格式信息
|
|
439
|
+
const mimeMatch = base64Data.match(/data:image\/(\w+);/);
|
|
440
|
+
if (mimeMatch && mimeMatch[1] && !format) {
|
|
441
|
+
format = mimeMatch[1] === 'jpeg' ? 'jpg' : mimeMatch[1];
|
|
442
|
+
}
|
|
443
|
+
// 提取纯Base64数据
|
|
444
|
+
base64Data = base64Data.substring(base64Index + 7);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const cmdObj = {
|
|
448
|
+
cmd_type: "loadImageFromBase64",
|
|
449
|
+
base64Data: base64Data,
|
|
450
|
+
format: format
|
|
398
451
|
};
|
|
399
452
|
this.sendWebSocketCommand(cmdObj);
|
|
400
453
|
}
|
|
@@ -437,6 +490,20 @@
|
|
|
437
490
|
this.sendWebSocketCommand(cmdObj);
|
|
438
491
|
}
|
|
439
492
|
|
|
493
|
+
/**
|
|
494
|
+
* 前端调整扫描结果图像顺序
|
|
495
|
+
* @param {number} oldIndex - 原图像索引
|
|
496
|
+
* @param {number} newIndex - 目标图像索引
|
|
497
|
+
*/
|
|
498
|
+
moveImage(oldIndex, newIndex) {
|
|
499
|
+
const cmdObj = {
|
|
500
|
+
cmd_type: "moveImage",
|
|
501
|
+
oldIndex: oldIndex,
|
|
502
|
+
newIndex: newIndex
|
|
503
|
+
};
|
|
504
|
+
this.sendWebSocketCommand(cmdObj);
|
|
505
|
+
}
|
|
506
|
+
|
|
440
507
|
/**
|
|
441
508
|
* 以pdf格式上传全部图像到服务器端
|
|
442
509
|
* @param {string} url - 上传URL
|
|
@@ -569,6 +636,79 @@
|
|
|
569
636
|
closeWebSocket() {
|
|
570
637
|
this.h5socket.close();
|
|
571
638
|
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* 批量从Base64数据加载多个图像
|
|
642
|
+
* @param {Array} base64Images - Base64图像数组,每个元素为 {data: 'base64字符串', format: '格式'}
|
|
643
|
+
*/
|
|
644
|
+
loadMultipleImagesFromBase64(base64Images) {
|
|
645
|
+
if (!Array.isArray(base64Images) || base64Images.length === 0) {
|
|
646
|
+
console.error('loadMultipleImagesFromBase64: 参数必须是非空数组');
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// 逐个加载图像
|
|
651
|
+
base64Images.forEach((image, index) => {
|
|
652
|
+
setTimeout(() => {
|
|
653
|
+
this.loadImageFromBase64(image.data, image.format || 'jpg');
|
|
654
|
+
}, index * 100); // 每个图像间隔100ms,避免同时发送过多数据
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* 从Canvas元素加载图像
|
|
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) {
|
|
665
|
+
if (!canvas || !(canvas instanceof HTMLCanvasElement)) {
|
|
666
|
+
console.error('loadImageFromCanvas: 参数必须是有效的Canvas元素');
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// 将Canvas转换为Base64
|
|
671
|
+
const mimeType = format === 'jpg' ? 'image/jpeg' : `image/${format}`;
|
|
672
|
+
const dataUrl = canvas.toDataURL(mimeType, quality);
|
|
673
|
+
|
|
674
|
+
// 提取Base64数据部分
|
|
675
|
+
const base64Data = dataUrl.split(',')[1];
|
|
676
|
+
|
|
677
|
+
// 调用Base64加载方法
|
|
678
|
+
this.loadImageFromBase64(base64Data, format);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* 从文件输入元素加载图像
|
|
683
|
+
* @param {HTMLInputElement} fileInput - 文件输入元素
|
|
684
|
+
*/
|
|
685
|
+
loadImageFromFileInput(fileInput) {
|
|
686
|
+
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
|
|
687
|
+
console.error('loadImageFromFileInput: 没有选择文件');
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
const files = Array.from(fileInput.files);
|
|
691
|
+
files.forEach((file, index) => {
|
|
692
|
+
// 检查是否为图像文件
|
|
693
|
+
if (!file.type.startsWith('image/')) {
|
|
694
|
+
console.warn(`跳过非图像文件: ${file.name}`);
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
const reader = new FileReader();
|
|
698
|
+
reader.onload = e => {
|
|
699
|
+
const dataUrl = e.target.result;
|
|
700
|
+
// 获取文件扩展名
|
|
701
|
+
const extension = file.name.split('.').pop().toLowerCase();
|
|
702
|
+
const format = extension === 'jpeg' ? 'jpg' : extension;
|
|
703
|
+
|
|
704
|
+
// 延迟加载,避免同时处理过多文件
|
|
705
|
+
setTimeout(() => {
|
|
706
|
+
this.loadImageFromBase64(dataUrl, format);
|
|
707
|
+
}, index * 100);
|
|
708
|
+
};
|
|
709
|
+
reader.readAsDataURL(file);
|
|
710
|
+
});
|
|
711
|
+
}
|
|
572
712
|
}
|
|
573
713
|
|
|
574
714
|
// CommonJS 兼容性导出
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* scanonweb v1.0.
|
|
2
|
+
* scanonweb v1.0.3
|
|
3
3
|
* ScanOnWeb - 扫描控件 JavaScript SDK,用于与本地扫描服务程序通信
|
|
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
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).ScanOnWeb=t()}(this,(function(){"use strict";class e{constructor(){this.scaner_work_config={showUI:!1,dpi_x:300,dpi_y:300,deviceIndex:0,showDialog:!1,autoFeedEnable:!0,autoFeed:!1,dupxMode:!1,autoDeskew:!1,autoBorderDetection:!1,colorMode:"RGB",transMode:"memory"},this.h5socket=null,this.imageCount=0,this.tryConnect()}getConnectedServer(e){return console.log("尝试连接托盘扫描服务websocket服务器..."),new Promise(((t,o)=>{const
|
|
9
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).ScanOnWeb=t()}(this,(function(){"use strict";class e{constructor(){this.scaner_work_config={showUI:!1,dpi_x:300,dpi_y:300,deviceIndex:0,showDialog:!1,autoFeedEnable:!0,autoFeed:!1,dupxMode:!1,autoDeskew:!1,autoBorderDetection:!1,colorMode:"RGB",transMode:"memory"},this.h5socket=null,this.imageCount=0,this.tryConnect()}getConnectedServer(e){return console.log("尝试连接托盘扫描服务websocket服务器..."),new Promise(((t,o)=>{const a=new WebSocket(e[0]);a.onopen=()=>{t(a)},a.onerror=e=>{o(e)}})).then((e=>(console.log("连接websocket服务器成功!"),this.initWebsocketCallback(e),console.log("尝试获取扫描设备列表..."),this.loadDevices(),e)),(t=>{if(e.length>1)return this.getConnectedServer(e.slice(1));throw t}))}tryConnect(){this.getConnectedServer(["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"])}initWebsocketCallback(e){this.h5socket=e,this.h5socket.onerror=this.onSocketError.bind(this),this.h5socket.onmessage=this.onSocketMessage.bind(this)}onSocketError(e){alert("无法连接扫描服务程序,请检查扫描服务程序是否已经启动!"),console.log("WebSocket error: "+e.data)}isCallbackExist(e){return!(!e||void 0===e||void 0===e)&&"function"==typeof e}onSocketMessage(e){const t=JSON.parse(e.data);switch(t.cmd_type){case"getDevicesList":this.isCallbackExist(this.onGetDevicesListEvent)&&this.onGetDevicesListEvent(t);break;case"scanComplete":this.imageCount=t.imageCount,this.isCallbackExist(this.onScanFinishedEvent)&&this.onScanFinishedEvent(t);break;case"selectScanDevice":this.scaner_work_config.deviceIndex=t.currentIndex,this.scaner_work_config.showDialog=t.showDialog,this.scaner_work_config.autoFeedEnable=t.autoFeedEnable,this.scaner_work_config.autoFeed=t.autoFeed,this.scaner_work_config.dupxMode=t.dupxMode,this.scaner_work_config.autoDeskew=t.autoDeskew,this.scaner_work_config.autoBorderDetection=t.autoBorderDetection,this.isCallbackExist(this.onSelectScanDeviceEvent)&&this.onSelectScanDeviceEvent(t);break;case"getImageCount":this.imageCount=t.imageCount,this.isCallbackExist(this.onGetImageCountEvent)&&this.onGetImageCountEvent(t);break;case"getAllImage":this.imageCount=t.imageCount,this.isCallbackExist(this.onGetAllImageEvent)&&this.onGetAllImageEvent(t);break;case"getImageById":this.imageCount=t.imageCount,this.isCallbackExist(this.onGetImageByIdEvent)&&this.onGetImageByIdEvent(t);break;case"loadImageFromUrl":this.imageCount=t.imageCount,this.isCallbackExist(this.onLoadImageFromUrlEvent)&&this.onLoadImageFromUrlEvent(t);break;case"loadImageFromBase64":this.imageCount=t.imageCount,this.isCallbackExist(this.onLoadImageFromBase64Event)&&this.onLoadImageFromBase64Event(t);break;case"rotateImage":this.imageCount=t.imageCount,this.isCallbackExist(this.onRotateImageEvent)&&this.onRotateImageEvent(t);break;case"getImageSize":this.imageCount=t.imageCount,this.isCallbackExist(this.onGetImageSizeEvent)&&this.onGetImageSizeEvent(t);break;case"uploadAllImageAsPdfToUrl":this.isCallbackExist(this.onUploadAllImageAsPdfToUrlEvent)&&this.onUploadAllImageAsPdfToUrlEvent(t);break;case"uploadAllImageAsTiffToUrl":this.isCallbackExist(this.onUploadAllImageAsTiffToUrlEvent)&&this.onUploadAllImageAsTiffToUrlEvent(t);break;case"uploadJpgImageByIndex":this.isCallbackExist(this.onUploadJpgImageByIndexEvent)&&this.onUploadJpgImageByIndexEvent(t);break;case"upload":this.imageCount=t.imageCount,this.isCallbackExist(this.onUploadEvent)&&this.onUploadEvent(t);break;case"imageEdited":this.isCallbackExist(this.onImageEditedEvent)&&this.onImageEditedEvent(t);break;case"imageDrap":this.isCallbackExist(this.onImageDrapEvent)&&this.onImageDrapEvent(t)}}sendWebSocketCommand(e){try{1===this.h5socket.readyState?this.h5socket.send(JSON.stringify(e)):alert("发送扫描指令失败!请刷新页面或者检查托盘扫描程序是否已经正常运行!")}catch(e){alert("发送扫描指令失败!"+e)}}setLicenseKey(e,t,o,a){const s={cmd_type:"setLicenseKey",licenseMode:e,key1:t,key2:o,url:a};this.sendWebSocketCommand(s)}loadDevices(){this.sendWebSocketCommand({cmd_type:"getDevicesList"})}selectScanDevice(e){const t={cmd_type:"selectScanDevice",deviceIndex:e};this.sendWebSocketCommand(t)}startScan(){const e={cmd_type:"startScan",config:this.scaner_work_config};this.sendWebSocketCommand(e)}clearAll(){this.sendWebSocketCommand({cmd_type:"clearAll"})}getImageCount(){this.sendWebSocketCommand({cmd_type:"getImageCount"})}getAllImage(){this.sendWebSocketCommand({cmd_type:"getAllImage"})}getImageById(e){const t={cmd_type:"getImageById",index:e};this.sendWebSocketCommand(t)}loadImageFromUrl(e,t){if(!t){const o=e.split(".").pop().toLowerCase();t="pdf"===o?"pdf":"tiff"===o||"tif"===o?"tiff":(["jpg","jpeg","png","bmp","gif","webp"].includes(o),"image")}const o={cmd_type:"loadImageFromUrl",url:e,type:t};this.sendWebSocketCommand(o)}loadImageFromBase64(e,t="jpg"){if(e.startsWith("data:")){const o=e.indexOf("base64,");if(-1!==o){const a=e.match(/data:image\/(\w+);/);a&&a[1]&&!t&&(t="jpeg"===a[1]?"jpg":a[1]),e=e.substring(o+7)}}const o={cmd_type:"loadImageFromBase64",base64Data:e,format:t};this.sendWebSocketCommand(o)}rotateImage(e,t){const o={cmd_type:"rotateImage",index:e,angle:t};this.sendWebSocketCommand(o)}getImageSize(e){const t={cmd_type:"getImageSize",index:e};this.sendWebSocketCommand(t)}deleteImageByIndex(e){const t={cmd_type:"deleteImageByIndex",index:e};this.sendWebSocketCommand(t)}moveImage(e,t){const o={cmd_type:"moveImage",oldIndex:e,newIndex:t};this.sendWebSocketCommand(o)}uploadAllImageAsPdfToUrl(e,t,o){const a={cmd_type:"uploadAllImageAsPdfToUrl",url:e,id:t,desc:o};this.sendWebSocketCommand(a)}uploadAllImageAsTiffToUrl(e,t,o){const a={cmd_type:"uploadAllImageAsTiffToUrl",url:e,id:t,desc:o};this.sendWebSocketCommand(a)}uploadJpgImageByIndex(e,t,o,a){const s={cmd_type:"uploadJpgImageByIndex",index:a,url:e,id:t,desc:o};this.sendWebSocketCommand(s)}saveAllImageToLocal(e){const t={cmd_type:"saveAllImageToLocal",filename:e};this.sendWebSocketCommand(t)}openClientLocalfile(){this.sendWebSocketCommand({cmd_type:"openClientLocalfile"})}ftpUploadAllImage(e,t,o,a,s,n){const i={cmd_type:"ftpUploadAllImage",serverIp:e,port:t,username:o,password:a,serverPath:s,filename:n};this.sendWebSocketCommand(i)}setUploadButtonVisible(e){const t={cmd_type:"setUploadButtonVisible",visible:e};this.sendWebSocketCommand(t)}setFocus(){this.sendWebSocketCommand({cmd_type:"focus"})}hidden(){this.sendWebSocketCommand({cmd_type:"hidden"})}closeWebSocket(){this.h5socket.close()}loadMultipleImagesFromBase64(e){Array.isArray(e)&&0!==e.length?e.forEach(((e,t)=>{setTimeout((()=>{this.loadImageFromBase64(e.data,e.format||"jpg")}),100*t)})):console.error("loadMultipleImagesFromBase64: 参数必须是非空数组")}loadImageFromCanvas(e,t="jpg",o=.9){if(!(e&&e instanceof HTMLCanvasElement))return void console.error("loadImageFromCanvas: 参数必须是有效的Canvas元素");const a="jpg"===t?"image/jpeg":`image/${t}`,s=e.toDataURL(a,o).split(",")[1];this.loadImageFromBase64(s,t)}loadImageFromFileInput(e){if(!e||!e.files||0===e.files.length)return void console.error("loadImageFromFileInput: 没有选择文件");Array.from(e.files).forEach(((e,t)=>{if(!e.type.startsWith("image/"))return void console.warn(`跳过非图像文件: ${e.name}`);const o=new FileReader;o.onload=o=>{const a=o.target.result,s=e.name.split(".").pop().toLowerCase(),n="jpeg"===s?"jpg":s;setTimeout((()=>{this.loadImageFromBase64(a,n)}),100*t)},o.readAsDataURL(e)}))}}return"undefined"!=typeof module&&module.exports&&(module.exports=e),"undefined"!=typeof window&&(window.ScanOnWeb=e),e}));
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -196,6 +196,13 @@ export default class ScanOnWeb {
|
|
|
196
196
|
*/
|
|
197
197
|
deleteImageByIndex(index: number): void;
|
|
198
198
|
|
|
199
|
+
/**
|
|
200
|
+
* 前端调整扫描结果图像顺序
|
|
201
|
+
* @param oldIndex 原图像索引
|
|
202
|
+
* @param newIndex 目标图像索引
|
|
203
|
+
*/
|
|
204
|
+
moveImage(oldIndex: number, newIndex: number): void;
|
|
205
|
+
|
|
199
206
|
/**
|
|
200
207
|
* 以pdf格式上传全部图像到服务器端
|
|
201
208
|
* @param url 上传URL
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ScanOnWeb - 扫描控件 JavaScript SDK
|
|
3
3
|
* https://www.brainysoft.cn 扫描控件官方网站,如需更多文档帮助请访问官网
|
|
4
|
-
* @version 1.0.
|
|
4
|
+
* @version 1.0.3
|
|
5
5
|
* @author BrainySoft
|
|
6
6
|
* @license MIT
|
|
7
7
|
*/
|
|
@@ -186,6 +186,14 @@ class ScanOnWeb {
|
|
|
186
186
|
}
|
|
187
187
|
break;
|
|
188
188
|
}
|
|
189
|
+
case "loadImageFromBase64": {
|
|
190
|
+
// 从Base64数据加载图片
|
|
191
|
+
this.imageCount = msg.imageCount;
|
|
192
|
+
if (this.isCallbackExist(this.onLoadImageFromBase64Event)) {
|
|
193
|
+
this.onLoadImageFromBase64Event(msg);
|
|
194
|
+
}
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
189
197
|
case "rotateImage": {
|
|
190
198
|
// 旋转图片
|
|
191
199
|
this.imageCount = msg.imageCount;
|
|
@@ -361,12 +369,58 @@ class ScanOnWeb {
|
|
|
361
369
|
|
|
362
370
|
/**
|
|
363
371
|
* 发送指令远程加载服务器端的多页图像到托盘服务
|
|
372
|
+
* 支持PDF、TIFF以及常见图像格式(JPG、PNG、BMP等)
|
|
364
373
|
* @param {string} url - 图像URL
|
|
374
|
+
* @param {string} [type] - 可选,指定文件类型:'pdf'、'tiff'、'image',如果不指定则根据URL扩展名自动判断
|
|
365
375
|
*/
|
|
366
|
-
loadImageFromUrl(url) {
|
|
376
|
+
loadImageFromUrl(url, type) {
|
|
377
|
+
// 如果没有指定类型,则根据URL扩展名自动判断
|
|
378
|
+
if (!type) {
|
|
379
|
+
const extension = url.split('.').pop().toLowerCase();
|
|
380
|
+
if (extension === 'pdf') {
|
|
381
|
+
type = 'pdf';
|
|
382
|
+
} else if (extension === 'tiff' || extension === 'tif') {
|
|
383
|
+
type = 'tiff';
|
|
384
|
+
} else if (['jpg', 'jpeg', 'png', 'bmp', 'gif', 'webp'].includes(extension)) {
|
|
385
|
+
type = 'image';
|
|
386
|
+
} else {
|
|
387
|
+
// 默认当作普通图像处理
|
|
388
|
+
type = 'image';
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
367
392
|
const cmdObj = {
|
|
368
393
|
cmd_type: "loadImageFromUrl",
|
|
369
394
|
url: url,
|
|
395
|
+
type: type
|
|
396
|
+
};
|
|
397
|
+
this.sendWebSocketCommand(cmdObj);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* 发送指令从Base64编码数据加载图像到托盘服务
|
|
402
|
+
* @param {string} base64Data - Base64编码的图像数据(不包含data:image/xxx;base64,前缀)
|
|
403
|
+
* @param {string} [format='jpg'] - 图像格式,如:'jpg'、'png'、'bmp'等,默认为'jpg'
|
|
404
|
+
*/
|
|
405
|
+
loadImageFromBase64(base64Data, format = 'jpg') {
|
|
406
|
+
// 如果base64数据包含data URL前缀,则去除它
|
|
407
|
+
if (base64Data.startsWith('data:')) {
|
|
408
|
+
const base64Index = base64Data.indexOf('base64,');
|
|
409
|
+
if (base64Index !== -1) {
|
|
410
|
+
// 尝试从data URL中提取格式信息
|
|
411
|
+
const mimeMatch = base64Data.match(/data:image\/(\w+);/);
|
|
412
|
+
if (mimeMatch && mimeMatch[1] && !format) {
|
|
413
|
+
format = mimeMatch[1] === 'jpeg' ? 'jpg' : mimeMatch[1];
|
|
414
|
+
}
|
|
415
|
+
// 提取纯Base64数据
|
|
416
|
+
base64Data = base64Data.substring(base64Index + 7);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const cmdObj = {
|
|
421
|
+
cmd_type: "loadImageFromBase64",
|
|
422
|
+
base64Data: base64Data,
|
|
423
|
+
format: format
|
|
370
424
|
};
|
|
371
425
|
this.sendWebSocketCommand(cmdObj);
|
|
372
426
|
}
|
|
@@ -409,6 +463,20 @@ class ScanOnWeb {
|
|
|
409
463
|
this.sendWebSocketCommand(cmdObj);
|
|
410
464
|
}
|
|
411
465
|
|
|
466
|
+
/**
|
|
467
|
+
* 前端调整扫描结果图像顺序
|
|
468
|
+
* @param {number} oldIndex - 原图像索引
|
|
469
|
+
* @param {number} newIndex - 目标图像索引
|
|
470
|
+
*/
|
|
471
|
+
moveImage(oldIndex, newIndex) {
|
|
472
|
+
const cmdObj = {
|
|
473
|
+
cmd_type: "moveImage",
|
|
474
|
+
oldIndex: oldIndex,
|
|
475
|
+
newIndex: newIndex,
|
|
476
|
+
};
|
|
477
|
+
this.sendWebSocketCommand(cmdObj);
|
|
478
|
+
}
|
|
479
|
+
|
|
412
480
|
/**
|
|
413
481
|
* 以pdf格式上传全部图像到服务器端
|
|
414
482
|
* @param {string} url - 上传URL
|
|
@@ -541,6 +609,82 @@ class ScanOnWeb {
|
|
|
541
609
|
closeWebSocket() {
|
|
542
610
|
this.h5socket.close();
|
|
543
611
|
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* 批量从Base64数据加载多个图像
|
|
615
|
+
* @param {Array} base64Images - Base64图像数组,每个元素为 {data: 'base64字符串', format: '格式'}
|
|
616
|
+
*/
|
|
617
|
+
loadMultipleImagesFromBase64(base64Images) {
|
|
618
|
+
if (!Array.isArray(base64Images) || base64Images.length === 0) {
|
|
619
|
+
console.error('loadMultipleImagesFromBase64: 参数必须是非空数组');
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// 逐个加载图像
|
|
624
|
+
base64Images.forEach((image, index) => {
|
|
625
|
+
setTimeout(() => {
|
|
626
|
+
this.loadImageFromBase64(image.data, image.format || 'jpg');
|
|
627
|
+
}, index * 100); // 每个图像间隔100ms,避免同时发送过多数据
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* 从Canvas元素加载图像
|
|
633
|
+
* @param {HTMLCanvasElement} canvas - Canvas元素
|
|
634
|
+
* @param {string} [format='jpg'] - 图像格式
|
|
635
|
+
* @param {number} [quality=0.9] - 图像质量(0-1之间,仅对jpg格式有效)
|
|
636
|
+
*/
|
|
637
|
+
loadImageFromCanvas(canvas, format = 'jpg', quality = 0.9) {
|
|
638
|
+
if (!canvas || !(canvas instanceof HTMLCanvasElement)) {
|
|
639
|
+
console.error('loadImageFromCanvas: 参数必须是有效的Canvas元素');
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// 将Canvas转换为Base64
|
|
644
|
+
const mimeType = format === 'jpg' ? 'image/jpeg' : `image/${format}`;
|
|
645
|
+
const dataUrl = canvas.toDataURL(mimeType, quality);
|
|
646
|
+
|
|
647
|
+
// 提取Base64数据部分
|
|
648
|
+
const base64Data = dataUrl.split(',')[1];
|
|
649
|
+
|
|
650
|
+
// 调用Base64加载方法
|
|
651
|
+
this.loadImageFromBase64(base64Data, format);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* 从文件输入元素加载图像
|
|
656
|
+
* @param {HTMLInputElement} fileInput - 文件输入元素
|
|
657
|
+
*/
|
|
658
|
+
loadImageFromFileInput(fileInput) {
|
|
659
|
+
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
|
|
660
|
+
console.error('loadImageFromFileInput: 没有选择文件');
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const files = Array.from(fileInput.files);
|
|
665
|
+
|
|
666
|
+
files.forEach((file, index) => {
|
|
667
|
+
// 检查是否为图像文件
|
|
668
|
+
if (!file.type.startsWith('image/')) {
|
|
669
|
+
console.warn(`跳过非图像文件: ${file.name}`);
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
const reader = new FileReader();
|
|
674
|
+
reader.onload = (e) => {
|
|
675
|
+
const dataUrl = e.target.result;
|
|
676
|
+
// 获取文件扩展名
|
|
677
|
+
const extension = file.name.split('.').pop().toLowerCase();
|
|
678
|
+
const format = extension === 'jpeg' ? 'jpg' : extension;
|
|
679
|
+
|
|
680
|
+
// 延迟加载,避免同时处理过多文件
|
|
681
|
+
setTimeout(() => {
|
|
682
|
+
this.loadImageFromBase64(dataUrl, format);
|
|
683
|
+
}, index * 100);
|
|
684
|
+
};
|
|
685
|
+
reader.readAsDataURL(file);
|
|
686
|
+
});
|
|
687
|
+
}
|
|
544
688
|
}
|
|
545
689
|
|
|
546
690
|
// ES6 模块导出
|
package/dist/index.d.ts
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ScanOnWeb - 扫描控件 JavaScript SDK
|
|
3
|
-
* TypeScript 定义文件
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 扫描配置参数接口
|
|
8
|
-
*/
|
|
9
|
-
export interface ScanConfig {
|
|
10
|
-
/** 是否显示扫描控件工作界面 */
|
|
11
|
-
showUI: boolean;
|
|
12
|
-
/** DPI 分辨率 X */
|
|
13
|
-
dpi_x: number;
|
|
14
|
-
/** DPI 分辨率 Y */
|
|
15
|
-
dpi_y: number;
|
|
16
|
-
/** 选中的扫描仪硬件设备id索引 */
|
|
17
|
-
deviceIndex: number;
|
|
18
|
-
/** 是否显示设备内置对话框 */
|
|
19
|
-
showDialog: boolean;
|
|
20
|
-
/** 是否使用自动进纸器 */
|
|
21
|
-
autoFeedEnable: boolean;
|
|
22
|
-
/** 是否自动装填纸张 */
|
|
23
|
-
autoFeed: boolean;
|
|
24
|
-
/** 是否使用双面扫描模式 */
|
|
25
|
-
dupxMode: boolean;
|
|
26
|
-
/** 是否使用自动纠偏模式 */
|
|
27
|
-
autoDeskew: boolean;
|
|
28
|
-
/** 是否使用自动边框检测 */
|
|
29
|
-
autoBorderDetection: boolean;
|
|
30
|
-
/** 色彩模式 */
|
|
31
|
-
colorMode: 'RGB' | 'BW' | 'GRAY';
|
|
32
|
-
/** 数据传输模式 */
|
|
33
|
-
transMode: 'memory' | 'file' | 'native';
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* WebSocket 消息接口
|
|
38
|
-
*/
|
|
39
|
-
export interface WebSocketMessage {
|
|
40
|
-
/** 命令类型 */
|
|
41
|
-
cmd_type: string;
|
|
42
|
-
/** 图像数量 */
|
|
43
|
-
imageCount?: number;
|
|
44
|
-
/** 当前设备索引 */
|
|
45
|
-
currentIndex?: number;
|
|
46
|
-
/** 其他属性 */
|
|
47
|
-
[key: string]: any;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 扫描控件类
|
|
52
|
-
*/
|
|
53
|
-
export default class ScanOnWeb {
|
|
54
|
-
/** 扫描配置参数 */
|
|
55
|
-
scaner_work_config: ScanConfig;
|
|
56
|
-
|
|
57
|
-
/** WebSocket 连接对象 */
|
|
58
|
-
h5socket: WebSocket | null;
|
|
59
|
-
|
|
60
|
-
/** 扫描结果图像总数 */
|
|
61
|
-
imageCount: number;
|
|
62
|
-
|
|
63
|
-
// 事件回调函数(可选)
|
|
64
|
-
onGetDevicesListEvent?: (msg: WebSocketMessage) => void;
|
|
65
|
-
onScanFinishedEvent?: (msg: WebSocketMessage) => void;
|
|
66
|
-
onSelectScanDeviceEvent?: (msg: WebSocketMessage) => void;
|
|
67
|
-
onGetImageCountEvent?: (msg: WebSocketMessage) => void;
|
|
68
|
-
onGetAllImageEvent?: (msg: WebSocketMessage) => void;
|
|
69
|
-
onGetImageByIdEvent?: (msg: WebSocketMessage) => void;
|
|
70
|
-
onLoadImageFromUrlEvent?: (msg: WebSocketMessage) => void;
|
|
71
|
-
onRotateImageEvent?: (msg: WebSocketMessage) => void;
|
|
72
|
-
onGetImageSizeEvent?: (msg: WebSocketMessage) => void;
|
|
73
|
-
onUploadAllImageAsPdfToUrlEvent?: (msg: WebSocketMessage) => void;
|
|
74
|
-
onUploadAllImageAsTiffToUrlEvent?: (msg: WebSocketMessage) => void;
|
|
75
|
-
onUploadJpgImageByIndexEvent?: (msg: WebSocketMessage) => void;
|
|
76
|
-
onUploadEvent?: (msg: WebSocketMessage) => void;
|
|
77
|
-
onImageEditedEvent?: (msg: WebSocketMessage) => void;
|
|
78
|
-
onImageDrapEvent?: (msg: WebSocketMessage) => void;
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* 构造函数
|
|
82
|
-
*/
|
|
83
|
-
constructor();
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* 通过连接多个websocket server端口返回一个可用的websocket连接对象
|
|
87
|
-
* @param wssUrls WebSocket服务器URL数组
|
|
88
|
-
* @returns WebSocket连接Promise
|
|
89
|
-
*/
|
|
90
|
-
getConnectedServer(wssUrls: string[]): Promise<WebSocket>;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* 尝试检测websocket哪个端口可以成功连接
|
|
94
|
-
*/
|
|
95
|
-
tryConnect(): void;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* 初始化websocket相关的函数绑定
|
|
99
|
-
* @param server WebSocket服务器实例
|
|
100
|
-
*/
|
|
101
|
-
initWebsocketCallback(server: WebSocket): void;
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* WebSocket错误处理
|
|
105
|
-
* @param event 错误事件
|
|
106
|
-
*/
|
|
107
|
-
onSocketError(event: Event): void;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* 判断回调函数是否存在
|
|
111
|
-
* @param f 要检查的函数
|
|
112
|
-
* @returns 函数是否存在且为函数类型
|
|
113
|
-
*/
|
|
114
|
-
isCallbackExist(f: any): f is Function;
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* WebSocket消息处理
|
|
118
|
-
* @param event WebSocket消息事件
|
|
119
|
-
*/
|
|
120
|
-
onSocketMessage(event: MessageEvent): void;
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* 通过websocket发送数据给webscoket服务端
|
|
124
|
-
* @param commandData 要发送的命令数据
|
|
125
|
-
*/
|
|
126
|
-
sendWebSocketCommand(commandData: object): void;
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* 设置授权信息
|
|
130
|
-
* @param licenseMode 授权模式
|
|
131
|
-
* @param key1 授权密钥1
|
|
132
|
-
* @param key2 授权密钥2
|
|
133
|
-
* @param licenseServerUrl 授权服务器URL
|
|
134
|
-
*/
|
|
135
|
-
setLicenseKey(licenseMode: string, key1: string, key2: string, licenseServerUrl: string): void;
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* 加载所有可用的扫描设备
|
|
139
|
-
*/
|
|
140
|
-
loadDevices(): void;
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* 设置当前选中的扫描设备id
|
|
144
|
-
* @param deviceIndex 设备索引
|
|
145
|
-
*/
|
|
146
|
-
selectScanDevice(deviceIndex: number): void;
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* 开始扫描
|
|
150
|
-
*/
|
|
151
|
-
startScan(): void;
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* 清除全部扫描结果
|
|
155
|
-
*/
|
|
156
|
-
clearAll(): void;
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* 获取图像总数
|
|
160
|
-
*/
|
|
161
|
-
getImageCount(): void;
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* 获取所有图像
|
|
165
|
-
*/
|
|
166
|
-
getAllImage(): void;
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* 发送指令获取某一页图像到托盘服务
|
|
170
|
-
* @param index 图像索引
|
|
171
|
-
*/
|
|
172
|
-
getImageById(index: number): void;
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* 发送指令远程加载服务器端的多页图像到托盘服务
|
|
176
|
-
* @param url 图像URL
|
|
177
|
-
*/
|
|
178
|
-
loadImageFromUrl(url: string): void;
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* 发送指令旋转某一页图像到托盘服务
|
|
182
|
-
* @param index 图像索引
|
|
183
|
-
* @param angle 旋转角度
|
|
184
|
-
*/
|
|
185
|
-
rotateImage(index: number, angle: number): void;
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* 发送指令获取某一页图像的宽度到托盘服务
|
|
189
|
-
* @param index 图像索引
|
|
190
|
-
*/
|
|
191
|
-
getImageSize(index: number): void;
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* 发送指令删除某一页图像到托盘服务
|
|
195
|
-
* @param index 图像索引
|
|
196
|
-
*/
|
|
197
|
-
deleteImageByIndex(index: number): void;
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* 以pdf格式上传全部图像到服务器端
|
|
201
|
-
* @param url 上传URL
|
|
202
|
-
* @param id 标识ID
|
|
203
|
-
* @param desc 描述信息
|
|
204
|
-
*/
|
|
205
|
-
uploadAllImageAsPdfToUrl(url: string, id: string, desc: string): void;
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* 以tiff格式上传全部图像到服务器端
|
|
209
|
-
* @param url 上传URL
|
|
210
|
-
* @param id 标识ID
|
|
211
|
-
* @param desc 描述信息
|
|
212
|
-
*/
|
|
213
|
-
uploadAllImageAsTiffToUrl(url: string, id: string, desc: string): void;
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* 以jpg格式上传某一页图像到服务器端
|
|
217
|
-
* @param url 上传URL
|
|
218
|
-
* @param id 标识ID
|
|
219
|
-
* @param desc 描述信息
|
|
220
|
-
* @param index 图像索引
|
|
221
|
-
*/
|
|
222
|
-
uploadJpgImageByIndex(url: string, id: string, desc: string, index: number): void;
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* 全部图像保存到客户端本地文件
|
|
226
|
-
* @param filename 文件名
|
|
227
|
-
*/
|
|
228
|
-
saveAllImageToLocal(filename: string): void;
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* 从客户端本地读取图像,通过打开文件对话框选择图像文件
|
|
232
|
-
*/
|
|
233
|
-
openClientLocalfile(): void;
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* ftp上传全部图像文件到服务器端
|
|
237
|
-
* @param serverIp 服务器IP
|
|
238
|
-
* @param port 端口
|
|
239
|
-
* @param username 用户名
|
|
240
|
-
* @param password 密码
|
|
241
|
-
* @param serverPath 服务器路径
|
|
242
|
-
* @param filename 文件名
|
|
243
|
-
*/
|
|
244
|
-
ftpUploadAllImage(serverIp: string, port: number, username: string, password: string, serverPath: string, filename: string): void;
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* 设置上传按钮是否可见
|
|
248
|
-
* @param visible 是否可见
|
|
249
|
-
*/
|
|
250
|
-
setUploadButtonVisible(visible: boolean): void;
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* 设置焦点
|
|
254
|
-
*/
|
|
255
|
-
setFocus(): void;
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* 隐藏窗口
|
|
259
|
-
*/
|
|
260
|
-
hidden(): void;
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* 关闭websocket连接
|
|
264
|
-
*/
|
|
265
|
-
closeWebSocket(): void;
|
|
266
|
-
}
|