You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular应用中连接扫描设备并实现浏览器端扫描预览?

Angular浏览器扫描设备连接与扫描件预览(开源方案)

核心方案选型

要实现浏览器直接连接扫描设备并预览扫描件,优先选择浏览器原生Web API配合轻量开源工具,无需付费依赖,主要有两个可行方向:


方案一:MediaDevices API(兼容性优先)

大多数带扫描功能的设备(如一体机、带扫描的摄像头)可被识别为视频输入设备,通过MediaDevices API获取设备流,捕获帧后转成图片显示在浏览器。

1. Angular组件实现代码

import { Component, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'app-scan-page',
  template: `
    <div class="scan-container">
      <h3>扫描设备连接提示</h3>
      <button (click)="startScan()" *ngIf="!isScanning">启动扫描</button>
      <button (click)="stopScan()" *ngIf="isScanning">停止扫描</button>
      <button (click)="captureScan()" *ngIf="isScanning">捕获扫描件</button>
      
      <video #scanVideo autoplay playsinline class="scan-video" *ngIf="isScanning"></video>
      
      <div class="scan-result" *ngIf="capturedImage">
        <h4>扫描预览</h4>
        <img [src]="capturedImage" alt="扫描文档" class="result-image">
      </div>
    </div>
  `,
  styles: [`
    .scan-container { max-width: 800px; margin: 20px auto; }
    .scan-video { width: 100%; border: 1px solid #eee; margin: 15px 0; }
    .result-image { max-width: 100%; border-radius: 4px; }
    button { margin-right: 10px; padding: 8px 16px; cursor: pointer; }
  `]
})
export class ScanPageComponent {
  @ViewChild('scanVideo') scanVideo!: ElementRef<HTMLVideoElement>;
  isScanning = false;
  capturedImage: string | null = null;
  mediaStream: MediaStream | null = null;

  async startScan() {
    try {
      // 获取扫描设备ID(筛选名称含"Scanner"/"扫描"的视频输入设备)
      const scanDeviceId = await this.getScanDeviceId();
      if (!scanDeviceId) {
        alert('未检测到可用扫描设备,请检查连接');
        return;
      }

      // 请求设备媒体流
      this.mediaStream = await navigator.mediaDevices.getUserMedia({
        video: {
          deviceId: { exact: scanDeviceId },
          width: { ideal: 1920 },
          height: { ideal: 1080 }
        }
      });

      // 绑定流到video元素
      this.scanVideo.nativeElement.srcObject = this.mediaStream;
      this.isScanning = true;
    } catch (err) {
      console.error('扫描设备连接失败:', err);
      alert('无法连接扫描设备,请授权浏览器访问权限并检查设备状态');
    }
  }

  async getScanDeviceId(): Promise<string | undefined> {
    const devices = await navigator.mediaDevices.enumerateDevices();
    return devices.find(device => 
      device.kind === 'videoinput' && 
      (device.label.includes('Scanner') || device.label.includes('扫描'))
    )?.deviceId;
  }

  captureScan() {
    if (!this.scanVideo.nativeElement) return;
    
    const canvas = document.createElement('canvas');
    canvas.width = this.scanVideo.nativeElement.videoWidth;
    canvas.height = this.scanVideo.nativeElement.videoHeight;
    
    const ctx = canvas.getContext('2d');
    ctx?.drawImage(this.scanVideo.nativeElement, 0, 0);
    
    // 转成base64图片直接显示
    this.capturedImage = canvas.toDataURL('image/png');
  }

  stopScan() {
    this.mediaStream?.getTracks().forEach(track => track.stop());
    this.mediaStream = null;
    this.isScanning = false;
  }
}

2. 关键注意事项

  • 必须在HTTPS环境下使用(本地开发localhost可例外)
  • 首次访问会触发浏览器权限请求,需用户授权设备访问
  • 部分老旧扫描仪可能无法被识别为视频输入设备,此时可切换到WebUSB方案

方案二:WebUSB API(针对独立USB扫描仪)

对于不支持MediaDevices的独立USB扫描仪,可通过WebUSB API直接与设备通信,前提是设备支持USB WebAPI规范。

1. 核心实现逻辑

// 需替换为你的扫描仪Vendor ID和对应通信协议
async connectUSBScan() {
  try {
    // 请求用户选择目标USB设备
    const device = await navigator.usb.requestDevice({
      filters: [{ vendorId: 0xXXXX }] // 替换为扫描仪的Vendor ID
    });

    await device.open();
    await device.selectConfiguration(1);
    await device.claimInterface(0);

    // 发送扫描指令(需参考扫描仪的USB协议文档)
    await device.controlTransferOut({
      requestType: 'class',
      recipient: 'interface',
      request: 0x06,
      value: 0x0100,
      index: 0x00
    });

    // 读取扫描返回数据并转成图片
    const transferResult = await device.transferIn(0x81, 65535);
    const blob = new Blob([transferResult.data], { type: 'image/png' });
    this.capturedImage = URL.createObjectURL(blob);
  } catch (err) {
    console.error('USB扫描设备连接失败:', err);
    alert('无法连接USB扫描仪,请检查设备驱动及协议兼容性');
  }
}

2. 注意事项

  • 需要提前获取扫描仪的Vendor ID/Product ID以及官方USB通信协议文档
  • 仅支持Chrome、Edge等现代浏览器,兼容性有限
  • 需用户手动选择设备,无法自动检测

开源库辅助方案

如果不想手写底层逻辑,可使用轻量开源库简化开发:

  • simple-scan:基于MediaDevices API封装,提供扫描、图像裁剪、亮度调整等功能,遵循MIT协议
  • 集成方式:安装后在Angular组件中调用,核心逻辑与方案一一致,库已封装设备筛选和图像处理细节

需求满足验证

  • 浏览器直接显示:通过将扫描帧转成base64或Blob URL,直接绑定到<img>元素,无需保存到本地设备
  • 开源免费:所有方案基于浏览器原生API或开源协议库,无付费依赖

内容的提问来源于stack exchange,提问作者Bharanitharan Sakthivel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:01:44