NexScanner Web SDK 使用说明

Copyright (c) 2026 侠医软件. All rights reserved.

NexScanner Web SDK 封装了插件的 WebSocket 协议。业务系统只需要调用 SDK 方法,不需要自己处理原生 WebSocket、二进制图片帧、Base64 分块拼接和命令响应匹配。

文件位置

文件说明
examples/sdk/nexscanner-sdk.js浏览器端 SDK
examples/sdk/nexscanner-sdk.d.tsTypeScript 类型声明
examples/sdk/nexscanner-sdk-demo.html完整 Demo
docs/NexScanner-Web-SDK使用说明.html本说明文档

快速开始

先启动 NexScanner 插件,并确认 WebSocket 服务已启用。默认地址:

ws://127.0.0.1:11345/

在页面中引入 SDK:

<script src="./nexscanner-sdk.js"></script>

最小示例:

<img id="preview">
<script>
const scanner = new NexScannerClient({ url: 'ws://127.0.0.1:11345/' });

scanner.on('image', image => {
  document.querySelector('#preview').src = image.url;
  console.log('收到扫描图片', image.seq, image.blob);
});

async function startScan() {
  await scanner.connect();
  const devices = await scanner.listScanners();
  await scanner.connectScanner(devices[0]);
  await scanner.setParams({
    resolution: 300,
    colormode: 2,
    duplex: 0,
    source: 1,
    format: 'jpg',
    backend: 'WIA',
    brightness: 0,
    contrast: 0
  });
  await scanner.scan();
}
</script>

创建客户端

const scanner = new NexScannerClient({
  url: 'ws://127.0.0.1:11345/',
  timeout: 15000,
  autoReconnect: false,
  reconnectDelay: 3000
});

连接与设备

await scanner.connect();
const devices = await scanner.listScanners();
await scanner.connectScanner(devices[0]);
await scanner.disconnectScanner();
scanner.disconnect();

扫描参数

await scanner.setParams({
  resolution: 300,
  colormode: 2,   // 0 黑白,1 灰度,2 彩色
  duplex: 0,      // 0 单面,1 双面
  source: 1,      // 0 自动,1 平板,2 ADF
  pageSize: 0,    // 纸张尺寸:0 A4(默认),1 A3,2 A5,3 A6,4 Letter,5 Legal,6 B5,7 自动
  orientation: 0, // 纸张方向:0 纵向(默认),1 横向(平板横放),2 自动(平板按横竖并集)
  format: 'jpg',
  backend: 'WIA', // WIA / TWAIN / SCAN
  brightness: 0,  // 亮度,部分扫描仪不支持
  contrast: 0     // 对比度,部分扫描仪不支持
});

const params = await scanner.getParams();
// params.pageSize        → 当前纸张尺寸索引
// params.pageSizeName    → 当前纸张尺寸名称,如 'A4'
// params.orientation     → 当前纸张方向索引
// params.orientationName → 当前纸张方向名称,如 'Portrait' / 'Landscape'
const status = await scanner.getStatus();

纸张尺寸(pageSize)

插件在 Windows(WIA/TWAIN) 与 Linux/国产系统(SANE) 三端统一按 pageSize 下发幅面,默认 A4。 这样做的原因:部分 A3 幅面扫描仪在 Linux/国产系统下 SANE 的后端默认幅面是 A3,而 Windows 驱动默认是 A4,不显式指定时两端结果会不一致。 选 7(自动)则沿用设备/驱动默认幅面。

// 方式一:合并到 setParams
await scanner.setParams({ pageSize: 0 });      // A4
await scanner.setParams({ pageSize: 'A3' });   // 也支持枚举名(SDK 自动转换)

// 方式二:单独调用
await scanner.setPaperSize('A3');
await scanner.setPaperSize(NexScannerClient.PaperSize.A4);

// 常量表(window.NexScannerPaperSize 同名可用)
NexScannerClient.PaperSize.A4;    // 0
NexScannerClient.PaperSize.A3;    // 1
NexScannerClient.PaperSize.Auto;  // 7

传了无法识别的值时 setParams / setPaperSize 会 reject(Invalid pageSize: xxx),不会再把这个参数发给插件。

纸张方向(orientation)

平板扫描时纸张可以竖放也可以横放:A4 竖放是 210×297,横放是 297×210。 只下发 pageSize 时扫描区域仍按 210×297 下发,横放的纸张会被裁掉,所以横放必须同时指定方向。

// 平板横放纸张
await scanner.setParams({ source: 1, pageSize: 0, orientation: 1 });

// 或者单独设置
await scanner.setPaperOrientation('landscape');
await scanner.setPaperOrientation(NexScannerClient.PaperOrientation.Landscape);

// 横竖都可能出现、不想每次切换 → 自动(平板按横竖并集 297×297 下发,ADF 仍按纵向)
await scanner.setPaperOrientation('auto');

NexScannerClient.PaperOrientation.Portrait;   // 0 纵向(默认)
NexScannerClient.PaperOrientation.Landscape;  // 1 横向
NexScannerClient.PaperOrientation.Auto;       // 2 自动

三端实现:WIA 改 Page Width/Height、TWAIN 用 ICAP_UNITS+ICAP_FRAMES 下发扫描区域、SANE 改 --page-width/--page-height。 若某台设备/TWAIN 驱动不支持 ICAP_FRAMES,插件会在扫描日志里给出告警,此时平板横向扫描请改用 WIA 后端。

开始和停止扫描

await scanner.scan();
await scanner.stopScan();

扫描图片由插件主动推送,结果通过 image 事件返回,不是 scan() 的返回值。

scanner.on('image', image => {
  console.log(image.seq);
  console.log(image.format);
  console.log(image.bytes); // ArrayBuffer
  console.log(image.blob);  // Blob
  console.log(image.url);   // 可直接给 img.src 使用
});

图片编辑

扫描图片编辑需要传入插件返回的图片序号 seq,会调用插件的 edit_image 接口。坐标和宽高均为相对比例,范围 0~1。

旋转

await scanner.rotateLeft(seq);
await scanner.rotateRight(seq);
await scanner.rotate180(seq);
await scanner.rotate(seq, 90);

裁剪

// 从图片 10%,10% 的位置开始,裁剪 80% 宽、80% 高
await scanner.crop(seq, 0.1, 0.1, 0.8, 0.8);

矩形标注、颜色、线条宽度

// 在图片上画红色矩形,线宽 3px
await scanner.annotateRect(seq, 0.1, 0.1, 0.5, 0.3, '#ff0000', 3);

// 蓝色粗线
await scanner.annotateRect(seq, 0.2, 0.2, 0.4, 0.2, '#0066ff', 8);

编辑后的图片通过 edit 事件返回:

scanner.on('edit', image => {
  document.querySelector('#preview').src = image.url;
});

Demo 中的裁剪和标注采用拖框模式:点击“裁剪”或“矩形标注”后,直接在大图预览区域拖动选择范围;Demo 会自动把拖框位置换算成 0~1 的相对坐标并调用 SDK。

选择本地图片

SDK 也提供本地图片选择能力。选择本地图片不需要连接插件,本地图片的旋转、裁剪、标注都在浏览器中完成,不调用插件接口。

const images = await scanner.pickLocalImages({
  multiple: true,
  accept: 'image/*'
});

const image = images[0];
document.querySelector('#preview').src = image.url;

本地图片编辑

本地图片没有插件返回的 seq,所以使用本地编辑方法;编辑结果会直接返回新的图片对象。Demo 中本地图片同样支持拖框裁剪和拖框标注。

const rotated = await scanner.rotateLocalImage(image, 90);
const cropped = await scanner.cropLocalImage(image, 0.1, 0.1, 0.8, 0.8);
const marked = await scanner.annotateLocalImage(image, 0.1, 0.1, 0.5, 0.3, '#ff0000', 3);

document.querySelector('#preview').src = marked.url;

事件列表

事件说明
openWebSocket 已连接
closeWebSocket 已断开
errorWebSocket 错误
send已发送命令
command收到命令响应
image收到扫描图片
edit收到编辑后的图片
image-meta收到图片元数据
edit-meta收到编辑元数据
text收到非 JSON 文本

自定义命令

如果后续插件新增命令,可以直接调用 command,不需要修改 SDK:

const resp = await scanner.command('get_status');

运行 Demo

在线体验(推荐,无需下载安装,浏览器直接打开):

https://www.ixiayi.net/scanner_client.htm

在线演示页与开发包内的 Demo 是同一套能力,日常联调建议直接用在线演示页;如需离线演示,打开包内 examples/sdk/nexscanner-sdk-demo.html,或把它放到任意静态 Web 服务中访问。

注意事项