scanonweb 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
1
  /*!
2
- * scanonweb v1.0.2
3
- * ScanOnWeb - 扫描控件 JavaScript SDK,用于与本地扫描服务程序通信
2
+ * scanonweb v2.0.0
3
+ * ScanOnWeb - 扫描控件 JavaScript SDK,支持 v2 协议、scanSource 和增量图像事件
4
4
  * https://www.brainysoft.cn
5
5
  *
6
- * Copyright (c) 2025 BrainySoft
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 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)}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}));
9
+ !function(e,o){"object"==typeof exports&&"undefined"!=typeof module?module.exports=o():"function"==typeof define&&define.amd?define(o):(e="undefined"!=typeof globalThis?globalThis:e||self).ScanOnWeb=o()}(this,(function(){"use strict";class e{constructor(){this.protocolVersion=2,this.serverProtocolVersion=null,this.imageCount=0,this.scaner_work_config={showUI:!1,dpi_x:300,dpi_y:300,deviceIndex:0,showDialog:!1,scanSource:"flatbed",autoFeed:!1,dupxMode:!1,autoDeskew:!1,autoBorderDetection:!1,colorMode:"RGB",transMode:"memory"},this.h5socket=null,this.tryConnect()}getConnectedServer(e){return console.log("尝试连接托盘扫描服务websocket服务器..."),new Promise(((o,t)=>{const a=new WebSocket(e[0]);a.onopen=()=>{o(a)},a.onerror=e=>{t(e)}})).then((e=>(console.log("连接websocket服务器成功!"),this.initWebsocketCallback(e),console.log("尝试获取扫描设备列表..."),this.loadDevices(),e)),(o=>{if(e.length>1)return this.getConnectedServer(e.slice(1));throw o}))}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}dispatchCallback(e,o){this.isCallbackExist(this[e])&&this[e](o)}toBoolCompat(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const o=e.trim().toLowerCase();return["1","true","yes","y","on","adf"].includes(o)}return!!e}toIntCompat(e,o){const t=Number(e);return Number.isInteger(t)?t:o}normalizeScanSource(e,o){if("string"==typeof e){const o=e.trim().toLowerCase();if("adf"===o||"feeder"===o||"documentfeeder"===o||"document_feeder"===o||"automatic_document_feeder"===o)return"adf";if("flatbed"===o||"flat_bed"===o||"platen"===o)return"flatbed"}return this.toBoolCompat(o)?"adf":"flatbed"}getLegacyAutoFeedEnable(e){return"adf"===this.normalizeScanSource(e)}shouldIncludeLegacyAutoFeedEnable(){return null===this.serverProtocolVersion||this.serverProtocolVersion<2}normalizeScanConfig(e,o){const t=Object.assign({},this.scaner_work_config,e||{}),a=!o||!1!==o.includeLegacyAutoFeedEnable,s={showUI:this.toBoolCompat(t.showUI),dpi_x:this.toIntCompat(t.dpi_x,300),dpi_y:this.toIntCompat(t.dpi_y,300),deviceIndex:this.toIntCompat(t.deviceIndex,0),showDialog:this.toBoolCompat(t.showDialog),scanSource:this.normalizeScanSource(t.scanSource,t.autoFeedEnable),autoFeed:this.toBoolCompat(t.autoFeed),dupxMode:this.toBoolCompat(t.dupxMode),autoDeskew:this.toBoolCompat(t.autoDeskew),autoBorderDetection:this.toBoolCompat(t.autoBorderDetection),colorMode:t.colorMode||"RGB",transMode:t.transMode||"memory"};return a&&(s.autoFeedEnable=this.getLegacyAutoFeedEnable(s.scanSource)),s}recordServerProtocolVersion(e){const o=this.toIntCompat(e&&e.protocolVersion,1);return this.serverProtocolVersion=o,o}applyIncomingScanConfig(e){this.scaner_work_config.deviceIndex=this.toIntCompat(e.currentIndex,this.scaner_work_config.deviceIndex),Object.prototype.hasOwnProperty.call(e,"showDialog")&&(this.scaner_work_config.showDialog=this.toBoolCompat(e.showDialog)),this.scaner_work_config.scanSource=this.normalizeScanSource(e.scanSource,e.autoFeedEnable),Object.prototype.hasOwnProperty.call(e,"autoFeed")&&(this.scaner_work_config.autoFeed=this.toBoolCompat(e.autoFeed)),Object.prototype.hasOwnProperty.call(e,"dupxMode")&&(this.scaner_work_config.dupxMode=this.toBoolCompat(e.dupxMode)),Object.prototype.hasOwnProperty.call(e,"autoDeskew")&&(this.scaner_work_config.autoDeskew=this.toBoolCompat(e.autoDeskew)),Object.prototype.hasOwnProperty.call(e,"autoBorderDetection")&&(this.scaner_work_config.autoBorderDetection=this.toBoolCompat(e.autoBorderDetection)),"string"==typeof e.colorMode&&e.colorMode&&(this.scaner_work_config.colorMode=e.colorMode),"string"==typeof e.transMode&&e.transMode&&(this.scaner_work_config.transMode=e.transMode),this.scaner_work_config.autoFeedEnable=this.getLegacyAutoFeedEnable(this.scaner_work_config.scanSource)}normalizeIncomingMessage(e){const o=Object.assign({},e||{}),t=this.recordServerProtocolVersion(o),a="string"==typeof o.cmd_type?o.cmd_type:"";switch(o.scanSource||(o.scanSource=this.normalizeScanSource(o.scanSource,o.autoFeedEnable)),a){case"getAllImage":o.cmd_type="imageListSnapshot";break;case"getImageById":o.cmd_type="imageSnapshot";break;case"imageDrap":o.cmd_type="imageMoved"}return o.protocolVersion||(o.protocolVersion=t),o}onSocketMessage(e){const o=JSON.parse(e.data),t=this.normalizeIncomingMessage(o);switch("number"==typeof t.imageCount&&(this.imageCount=t.imageCount),t.cmd_type){case"getDevicesList":this.dispatchCallback("onGetDevicesListEvent",t);break;case"scanComplete":this.dispatchCallback("onScanFinishedEvent",t);break;case"selectScanDevice":this.applyIncomingScanConfig(t),this.dispatchCallback("onSelectScanDeviceEvent",t);break;case"getImageCount":this.dispatchCallback("onGetImageCountEvent",t);break;case"imageListSnapshot":this.dispatchCallback("onImageListSnapshotEvent",t),this.dispatchCallback("onGetAllImageEvent",t);break;case"imageSnapshot":this.dispatchCallback("onImageSnapshotEvent",t),this.dispatchCallback("onGetImageByIdEvent",t);break;case"scanPageAdded":this.dispatchCallback("onScanPageAddedEvent",t);break;case"loadImageFromUrl":this.dispatchCallback("onLoadImageFromUrlEvent",t);break;case"loadImageFromBase64":this.dispatchCallback("onLoadImageFromBase64Event",t);break;case"rotateImage":this.dispatchCallback("onRotateImageEvent",t);break;case"getImageSize":this.dispatchCallback("onGetImageSizeEvent",t);break;case"uploadAllImageAsPdfToUrl":this.dispatchCallback("onUploadAllImageAsPdfToUrlEvent",t);break;case"uploadAllImageAsTiffToUrl":this.dispatchCallback("onUploadAllImageAsTiffToUrlEvent",t);break;case"uploadJpgImageByIndex":this.dispatchCallback("onUploadJpgImageByIndexEvent",t);break;case"upload":this.dispatchCallback("onUploadEvent",t);break;case"imageEdited":this.dispatchCallback("onImageEditedEvent",t);break;case"imageMoved":this.dispatchCallback("onImageMovedEvent",t),this.dispatchCallback("onImageDrapEvent",t);break;case"imageDeleted":this.dispatchCallback("onImageDeletedEvent",t);break;case"imagesCleared":this.dispatchCallback("onImagesClearedEvent",t)}}normalizeOutgoingCommand(e){const o=Object.assign({},e||{});return o.protocolVersion=this.protocolVersion,"startScan"===o.cmd_type&&(o.config=this.normalizeScanConfig(o.config||this.scaner_work_config,{includeLegacyAutoFeedEnable:this.shouldIncludeLegacyAutoFeedEnable()})),o}sendWebSocketCommand(e){try{this.h5socket&&1===this.h5socket.readyState?this.h5socket.send(JSON.stringify(this.normalizeOutgoingCommand(e))):alert("发送扫描指令失败!请刷新页面或者检查托盘扫描程序是否已经正常运行!")}catch(e){alert("发送扫描指令失败!"+e)}}setLicenseKey(e,o,t,a){this.sendWebSocketCommand({cmd_type:"setLicenseKey",licenseMode:e,key1:o,key2:t,url:a})}loadDevices(){this.sendWebSocketCommand({cmd_type:"getDevicesList"})}selectScanDevice(e){this.sendWebSocketCommand({cmd_type:"selectScanDevice",deviceIndex:e})}startScan(){this.sendWebSocketCommand({cmd_type:"startScan",config:this.scaner_work_config})}clearAll(){this.sendWebSocketCommand({cmd_type:"clearAll"})}getImageCount(){this.sendWebSocketCommand({cmd_type:"getImageCount"})}getAllImage(){this.sendWebSocketCommand({cmd_type:"getAllImage"})}getImageById(e){const o={cmd_type:"getImageById"};"string"==typeof e&&e.trim()?o.imageId=e.trim():o.index=e,this.sendWebSocketCommand(o)}loadImageFromUrl(e,o){if(!o){const t=e.split(".").pop().toLowerCase();o="pdf"===t?"pdf":"tiff"===t||"tif"===t?"tiff":(["jpg","jpeg","png","bmp","gif","webp"].includes(t),"image")}this.sendWebSocketCommand({cmd_type:"loadImageFromUrl",url:e,type:o})}loadImageFromBase64(e,o){let t=o||"jpg",a=e;if(a.startsWith("data:")){const e=a.indexOf("base64,");if(-1!==e){if(!o){const e=a.match(/data:image\/(\w+);/);e&&e[1]&&(t="jpeg"===e[1]?"jpg":e[1])}a=a.substring(e+7)}}this.sendWebSocketCommand({cmd_type:"loadImageFromBase64",base64Data:a,format:t})}rotateImage(e,o){this.sendWebSocketCommand({cmd_type:"rotateImage",index:e,angle:o})}getImageSize(e){this.sendWebSocketCommand({cmd_type:"getImageSize",index:e})}deleteImageByIndex(e,o){const t={cmd_type:"deleteImageByIndex",index:e};"string"==typeof o&&o.trim()&&(t.imageId=o.trim()),this.sendWebSocketCommand(t)}moveImage(e,o){this.sendWebSocketCommand({cmd_type:"moveImage",oldIndex:e,newIndex:o})}uploadAllImageAsPdfToUrl(e,o,t){this.sendWebSocketCommand({cmd_type:"uploadAllImageAsPdfToUrl",url:e,id:o,desc:t})}uploadAllImageAsTiffToUrl(e,o,t){this.sendWebSocketCommand({cmd_type:"uploadAllImageAsTiffToUrl",url:e,id:o,desc:t})}uploadJpgImageByIndex(e,o,t,a){this.sendWebSocketCommand({cmd_type:"uploadJpgImageByIndex",index:a,url:e,id:o,desc:t})}saveAllImageToLocal(e){this.sendWebSocketCommand({cmd_type:"saveAllImageToLocal",filename:e})}openClientLocalfile(){this.sendWebSocketCommand({cmd_type:"openClientLocalfile"})}ftpUploadAllImage(e,o,t,a,s,n){this.sendWebSocketCommand({cmd_type:"ftpUploadAllImage",serverIp:e,port:o,username:t,password:a,serverPath:s,filename:n})}setUploadButtonVisible(e){this.sendWebSocketCommand({cmd_type:"setUploadButtonVisible",visible:e})}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,o)=>{setTimeout((()=>{this.loadImageFromBase64(e.data,e.format||"jpg")}),100*o)})):console.error("loadMultipleImagesFromBase64: 参数必须是非空数组")}loadImageFromCanvas(e,o,t){const a=o||"jpg",s="number"==typeof t?t:.9;if(!(e&&e instanceof HTMLCanvasElement))return void console.error("loadImageFromCanvas: 参数必须是有效的Canvas元素");const n="jpg"===a?"image/jpeg":"image/"+a,i=e.toDataURL(n,s).split(",")[1];this.loadImageFromBase64(i,a)}loadImageFromFileInput(e){if(!e||!e.files||0===e.files.length)return void console.error("loadImageFromFileInput: 没有选择文件");Array.from(e.files).forEach(((e,o)=>{if(!e.type.startsWith("image/"))return void console.warn("跳过非图像文件: "+e.name);const t=new FileReader;t.onload=t=>{const a=t.target.result,s=e.name.split(".").pop().toLowerCase(),n="jpeg"===s?"jpg":s;setTimeout((()=>{this.loadImageFromBase64(a,n)}),100*o)},t.readAsDataURL(e)}))}}return"undefined"!=typeof module&&module.exports&&(module.exports=e),"undefined"!=typeof window&&(window.ScanOnWeb=e),e}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "scanonweb",
3
- "version": "1.0.2",
4
- "description": "ScanOnWeb - 扫描控件 JavaScript SDK,用于与本地扫描服务程序通信",
3
+ "version": "2.0.0",
4
+ "description": "ScanOnWeb - 扫描控件 JavaScript SDK,支持 v2 协议、scanSource 和增量图像事件",
5
5
  "main": "dist/scanonweb.cjs.js",
6
6
  "module": "dist/scanonweb.esm.js",
7
7
  "browser": "dist/scanonweb.umd.js",
@@ -13,7 +13,8 @@
13
13
  "LICENSE"
14
14
  ],
15
15
  "scripts": {
16
- "build": "rollup -c",
16
+ "build": "npm run clean && rollup -c && npm run copy:types",
17
+ "copy:types": "node scripts/copy-types.js",
17
18
  "dev": "rollup -c -w",
18
19
  "test": "echo \"Error: no test specified\" && exit 1",
19
20
  "prepublishOnly": "npm run build",
package/src/index.d.ts CHANGED
@@ -1,73 +1,96 @@
1
- /**
2
- * ScanOnWeb - 扫描控件 JavaScript SDK
3
- * TypeScript 定义文件
4
- */
1
+ export type ScanSource = "flatbed" | "adf";
2
+ export type ColorMode = "RGB" | "BW" | "GRAY";
3
+ export type TransferMode = "memory" | "file" | "native";
5
4
 
6
- /**
7
- * 扫描配置参数接口
8
- */
9
5
  export interface ScanConfig {
10
- /** 是否显示扫描控件工作界面 */
11
6
  showUI: boolean;
12
- /** DPI 分辨率 X */
13
7
  dpi_x: number;
14
- /** DPI 分辨率 Y */
15
8
  dpi_y: number;
16
- /** 选中的扫描仪硬件设备id索引 */
17
9
  deviceIndex: number;
18
- /** 是否显示设备内置对话框 */
19
10
  showDialog: boolean;
20
- /** 是否使用自动进纸器 */
21
- autoFeedEnable: boolean;
22
- /** 是否自动装填纸张 */
11
+ scanSource: ScanSource;
23
12
  autoFeed: boolean;
24
- /** 是否使用双面扫描模式 */
25
13
  dupxMode: boolean;
26
- /** 是否使用自动纠偏模式 */
27
14
  autoDeskew: boolean;
28
- /** 是否使用自动边框检测 */
29
15
  autoBorderDetection: boolean;
30
- /** 色彩模式 */
31
- colorMode: 'RGB' | 'BW' | 'GRAY';
32
- /** 数据传输模式 */
33
- transMode: 'memory' | 'file' | 'native';
16
+ colorMode: ColorMode;
17
+ transMode: TransferMode;
18
+ /** Legacy compatibility only. Prefer `scanSource`. */
19
+ autoFeedEnable?: boolean;
20
+ }
21
+
22
+ export interface ImageInfo {
23
+ index: number;
24
+ imageId?: string;
25
+ width?: number;
26
+ height?: number;
27
+ imageBase64?: string;
28
+ [key: string]: any;
34
29
  }
35
30
 
36
- /**
37
- * WebSocket 消息接口
38
- */
39
31
  export interface WebSocketMessage {
40
- /** 命令类型 */
41
32
  cmd_type: string;
42
- /** 图像数量 */
33
+ protocolVersion?: number;
34
+ ok?: boolean;
35
+ success?: boolean;
43
36
  imageCount?: number;
44
- /** 当前设备索引 */
45
37
  currentIndex?: number;
46
- /** 其他属性 */
38
+ currentSelected?: number;
39
+ selectedImageId?: string | null;
40
+ imageId?: string;
41
+ imageIndex?: number;
42
+ index?: number;
43
+ oldIndex?: number;
44
+ newIndex?: number;
45
+ beforeIndex?: number;
46
+ afterIndex?: number;
47
+ beforeImageCount?: number;
48
+ afterImageCount?: number;
49
+ scanSource?: ScanSource;
50
+ autoFeedEnable?: boolean;
51
+ autoFeed?: boolean;
52
+ dupxMode?: boolean;
53
+ autoDeskew?: boolean;
54
+ autoBorderDetection?: boolean;
55
+ colorMode?: ColorMode | string;
56
+ transMode?: TransferMode | string;
57
+ scanJobId?: string;
58
+ source?: string;
59
+ loadedCount?: number;
60
+ imageAfterCount?: number;
61
+ images?: string[];
62
+ imageInfos?: ImageInfo[];
63
+ imageBase64?: string;
64
+ devices?: any[];
47
65
  [key: string]: any;
48
66
  }
49
67
 
50
- /**
51
- * 扫描控件类
52
- */
68
+ export interface Base64ImagePayload {
69
+ data: string;
70
+ format?: string;
71
+ }
72
+
53
73
  export default class ScanOnWeb {
54
- /** 扫描配置参数 */
55
- scaner_work_config: ScanConfig;
56
-
57
- /** WebSocket 连接对象 */
74
+ protocolVersion: number;
75
+ serverProtocolVersion: number | null;
76
+ scaner_work_config: ScanConfig & {
77
+ /** Legacy compatibility only. Prefer `scanSource`. */
78
+ autoFeedEnable?: boolean;
79
+ };
58
80
  h5socket: WebSocket | null;
59
-
60
- /** 扫描结果图像总数 */
61
81
  imageCount: number;
62
82
 
63
- // 事件回调函数(可选)
64
83
  onGetDevicesListEvent?: (msg: WebSocketMessage) => void;
65
84
  onScanFinishedEvent?: (msg: WebSocketMessage) => void;
66
85
  onSelectScanDeviceEvent?: (msg: WebSocketMessage) => void;
67
86
  onGetImageCountEvent?: (msg: WebSocketMessage) => void;
87
+ onImageListSnapshotEvent?: (msg: WebSocketMessage) => void;
88
+ onImageSnapshotEvent?: (msg: WebSocketMessage) => void;
89
+ onScanPageAddedEvent?: (msg: WebSocketMessage) => void;
68
90
  onGetAllImageEvent?: (msg: WebSocketMessage) => void;
69
91
  onGetImageByIdEvent?: (msg: WebSocketMessage) => void;
70
92
  onLoadImageFromUrlEvent?: (msg: WebSocketMessage) => void;
93
+ onLoadImageFromBase64Event?: (msg: WebSocketMessage) => void;
71
94
  onRotateImageEvent?: (msg: WebSocketMessage) => void;
72
95
  onGetImageSizeEvent?: (msg: WebSocketMessage) => void;
73
96
  onUploadAllImageAsPdfToUrlEvent?: (msg: WebSocketMessage) => void;
@@ -75,192 +98,83 @@ export default class ScanOnWeb {
75
98
  onUploadJpgImageByIndexEvent?: (msg: WebSocketMessage) => void;
76
99
  onUploadEvent?: (msg: WebSocketMessage) => void;
77
100
  onImageEditedEvent?: (msg: WebSocketMessage) => void;
101
+ onImageMovedEvent?: (msg: WebSocketMessage) => void;
78
102
  onImageDrapEvent?: (msg: WebSocketMessage) => void;
103
+ onImageDeletedEvent?: (msg: WebSocketMessage) => void;
104
+ onImagesClearedEvent?: (msg: WebSocketMessage) => void;
79
105
 
80
- /**
81
- * 构造函数
82
- */
83
106
  constructor();
84
107
 
85
- /**
86
- * 通过连接多个websocket server端口返回一个可用的websocket连接对象
87
- * @param wssUrls WebSocket服务器URL数组
88
- * @returns WebSocket连接Promise
89
- */
90
108
  getConnectedServer(wssUrls: string[]): Promise<WebSocket>;
91
-
92
- /**
93
- * 尝试检测websocket哪个端口可以成功连接
94
- */
95
109
  tryConnect(): void;
96
-
97
- /**
98
- * 初始化websocket相关的函数绑定
99
- * @param server WebSocket服务器实例
100
- */
101
110
  initWebsocketCallback(server: WebSocket): void;
102
-
103
- /**
104
- * WebSocket错误处理
105
- * @param event 错误事件
106
- */
107
111
  onSocketError(event: Event): void;
108
-
109
- /**
110
- * 判断回调函数是否存在
111
- * @param f 要检查的函数
112
- * @returns 函数是否存在且为函数类型
113
- */
114
112
  isCallbackExist(f: any): f is Function;
115
-
116
- /**
117
- * WebSocket消息处理
118
- * @param event WebSocket消息事件
119
- */
113
+ dispatchCallback(name: string, msg: WebSocketMessage): void;
114
+ toBoolCompat(value: any): boolean;
115
+ toIntCompat(value: any, fallback: number): number;
116
+ normalizeScanSource(
117
+ scanSource?: string | null,
118
+ legacyAutoFeedEnable?: any
119
+ ): ScanSource;
120
+ getLegacyAutoFeedEnable(scanSource?: string | null): boolean;
121
+ shouldIncludeLegacyAutoFeedEnable(): boolean;
122
+ normalizeScanConfig(
123
+ config?: Partial<ScanConfig> & { autoFeedEnable?: boolean },
124
+ options?: { includeLegacyAutoFeedEnable?: boolean }
125
+ ): ScanConfig & { autoFeedEnable?: boolean };
126
+ recordServerProtocolVersion(msg: WebSocketMessage): number;
127
+ applyIncomingScanConfig(msg: WebSocketMessage): void;
128
+ normalizeIncomingMessage(rawMsg: WebSocketMessage): WebSocketMessage;
120
129
  onSocketMessage(event: MessageEvent): void;
121
-
122
- /**
123
- * 通过websocket发送数据给webscoket服务端
124
- * @param commandData 要发送的命令数据
125
- */
130
+ normalizeOutgoingCommand(commandData: Record<string, any>): Record<string, any>;
126
131
  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
- */
132
+ setLicenseKey(
133
+ licenseMode: string,
134
+ key1: string,
135
+ key2: string,
136
+ licenseServerUrl: string
137
+ ): void;
140
138
  loadDevices(): void;
141
-
142
- /**
143
- * 设置当前选中的扫描设备id
144
- * @param deviceIndex 设备索引
145
- */
146
139
  selectScanDevice(deviceIndex: number): void;
147
-
148
- /**
149
- * 开始扫描
150
- */
151
140
  startScan(): void;
152
-
153
- /**
154
- * 清除全部扫描结果
155
- */
156
141
  clearAll(): void;
157
-
158
- /**
159
- * 获取图像总数
160
- */
161
142
  getImageCount(): void;
162
-
163
- /**
164
- * 获取所有图像
165
- */
166
143
  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
- */
144
+ getImageById(indexOrImageId: number | string): void;
145
+ loadImageFromUrl(url: string, type?: string): void;
146
+ loadImageFromBase64(base64Data: string, format?: string): void;
185
147
  rotateImage(index: number, angle: number): void;
186
-
187
- /**
188
- * 发送指令获取某一页图像的宽度到托盘服务
189
- * @param index 图像索引
190
- */
191
148
  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
- */
149
+ deleteImageByIndex(index: number, imageId?: string): void;
150
+ moveImage(oldIndex: number, newIndex: number): void;
205
151
  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
152
  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
- */
153
+ uploadJpgImageByIndex(
154
+ url: string,
155
+ id: string,
156
+ desc: string,
157
+ index: number
158
+ ): void;
228
159
  saveAllImageToLocal(filename: string): void;
229
-
230
- /**
231
- * 从客户端本地读取图像,通过打开文件对话框选择图像文件
232
- */
233
160
  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
- */
161
+ ftpUploadAllImage(
162
+ serverIp: string,
163
+ port: number,
164
+ username: string,
165
+ password: string,
166
+ serverPath: string,
167
+ filename: string
168
+ ): void;
250
169
  setUploadButtonVisible(visible: boolean): void;
251
-
252
- /**
253
- * 设置焦点
254
- */
255
170
  setFocus(): void;
256
-
257
- /**
258
- * 隐藏窗口
259
- */
260
171
  hidden(): void;
261
-
262
- /**
263
- * 关闭websocket连接
264
- */
265
172
  closeWebSocket(): void;
173
+ loadMultipleImagesFromBase64(base64Images: Base64ImagePayload[]): void;
174
+ loadImageFromCanvas(
175
+ canvas: HTMLCanvasElement,
176
+ format?: string,
177
+ quality?: number
178
+ ): void;
179
+ loadImageFromFileInput(fileInput: HTMLInputElement): void;
266
180
  }