最近项目有个需求:将文件通过购买的富士通扫描仪扫描到本地,扫描完成后自动上传到服务器,并关联相关单据。
相关注意事项如下:
1.购买的扫描仪提供的开发文档说是使用ActiveX 控件,所以必须用IE浏览器,且必须是windows环境
2.使用vue开发的项目,需要使用vue接入ActiveX控件
3.将扫描到本地的文件自动上传到服务器上
4.更新表单文件

具体实现方法如下:
首先在index.html中初始化扫描仪:

<script>
    //初始化扫描仪配置
 /*orderDocument表示当前单据编号,用于给扫描后的文件命名。length是为了给文件有序化命名,比如当前扫描了两个文件(orderDocument_001.jpg,orderDocument_002.jpg,),下次再次扫描的时候方便从_003开始全名*/
      function InitSettings (orderDocument,length) {
        /*FileName 本属性设置储存图像数据的文件名称(不包括扩展名);
         *储存图像数据的文件名称(包括绝对路径,以“\0”结束); 不要指定扩展名,由控件根据 FileType 属性指定;
         * 本属性只在 ScanTo 属性为“0 – 文件”时有效; 实际的文件名称通过以下方式确定:在本属性指定的文件名后面添加三位数字序列号, 后面是 FileType 属性指定的图像数据类型的扩展名;
         例如,当 FileType 属性设置为“1 - TIFF”且 FileName 属性设置为“C:\image\img”时扫 描三个文件,则在 C:\image\文件夹中创建名为 img001.tif、img002.tif 和 img003.tif 的三 个图像文件;
         如果存在同名文件,则会根据 Overwrite 属性设定值来处理; 如果指定文件名中包含“\ * ? “ < > |”中的任意非法字符,则无法创建文件; 可以使用“#”通配符来指定 1 至 5 位数字序列号,
         例如:
         img# img###vvv img#####v
         -> img1
         -> img001vvv -> img00001v
         当 FileNumber2 设置为-1 时,将不会在文件名中添加数字序列号;
         * */
        fhkScan.FileName = 'D:\\scanImage\\'+orderDocument+'_';
        fhkScan.FileNumber2 = parseInt(length);
        /*PixelType 像素类型: 0 – 黑白(初始值) 1 – 灰度 2 – 彩色 3 – 自动
         说明
         本属性用于设置将要读取的像素数据类型;
         当 FileType 属性设置为“3 - JPEG”时,本属性不能设置为“0 – 黑白”;
         当 CompressionType 属性设置为“0 – 无压缩”时,本属性才能设置为“3 – 自动”;
         */
        fhkScan.PixelType = 2;
        /* FileType 文件类型(图像数据格式) 0 – BMP : Windows 位图文件 1 – TIFF : TIFF 文件(初始值)
         2– 多页TIFF: 多页TIFF文件 3 – JPEG : JPEG 文件
         4 – PDF : PDF 文件
         5– 多页PDF: 多页PDF文件
         本属性只在 ScanTo 属性为“0 – 文件”时有效;
         当本属性设置为“1 – TIFF”或“2 – 多页 TIFF”,PixelType 属性设置为“1 – 灰度”或“2 – 彩色”时,CompressionType 属性必须设置为“0 – 无压缩”或“5 – JPEG”;
         当本属性设置为“3 – JPEG”时,PixelType 属性必须设置为“1 – 灰度”或“2 – 彩色”; 当本属性设置为“4 – PDF”或“5 – 多页 PDF”时,如果 PixelType 属性设置为“0 – 黑 白”,则 CompressionType 属性必须设置为“5 – JPEG”以外的任何值;如果 PixelType 属 性设置为“1 – 灰度”或“2 – 彩色”时,CompressionType 属性必须设置为“0 – 无压 缩”或“5 – JPEG”;
         *
         * */
        fhkScan.FileType = 3;
        /*CompressionType 数据压缩类型
         0 – 无压缩
         1 – CCITT G3(1D) : MH 压缩
         2 – CCITT G3(2D) KFactor = 2 : MR 压缩,K Factor 为 2
         3 – CCITT G3(2D) KFactor = 4 : MR 压缩,K Factor 为 4
         4 – CCITT G4 : MMR 压缩(初始值)
         5 – JPEG : JPEG 压缩
         本属性在如下情况下有效:ScanTo 属性设置为“0 – 文件”且 FileType 属性设置为“1 – TIFF”、“2 – 多页 TIFF”、“4 – PDF”、“5 – 多页 PDF”或者 ScanTo 属性设置为“2 – 原始 图像句柄”;其他情况下忽略本属性;
         当 FileType 属性设置为“0 – BMP”时,本属性自动设定为“0 – 无压缩”;
         当 FileType 属性设置为“3 – JPEG”时,本属性自动设定为“5 – JPEG”; 本属性的设定值中“1 – CCITT G3(1D)”、“2 – CCITT G3(2D) KFactor = 2”、“3 – CCITT G3(2D) KFactor = 4”、“4 – CCITT G4”适用于黑白数据,“5 – JPEG”适用于彩色数据;
         如果 PixelType 属性设置为“1 – 灰度”或“2 – 彩色”,而本属性设置为适用于黑白数 据的压缩方式,则扫描将会被设定为黑白模式,即 PixelType 属性自动设定为“0 – 黑白”;
         * */
        fhkScan.CompressionType = 5;
        /* JPEG 数据压缩水平
        *设定值
         0 – 水平 1 : 压缩水平 1(文件大小优先)
         1 – 水平 2 : 压缩水平 2
         2 – 水平 3 : 压缩水平 3
         3 – 水平 4 : 压缩水平 4
         4 – 水平 5 : 压缩水平 5(初始值)
         5 – 水平 6 : 压缩水平 6
         6 – 水平 7 : 压缩水平 7(图像质量优先)
        * */
        fhkScan.JPGQuality = 2;
        /*PaperSupply进纸模式
         0 – 平板 1 – ADF 正面(初始值) 2 – ADF 双面
         当设备支持平板时才能设置本属性为“0 – 平板”;当设备支持 ADF 时才能设置本属性 为“1 – ADF 正面”或“2 – ADF 双面”;
         * */
        fhkScan.PaperSupply = 1;
        fhkScan.ScanRotate = 0;
        fhkScan.Resolution = 7;// 800x800 dpi
        fhkScan.SkipWhitePage = 6;
        fhkScan.ShowSourceUI = false;
        fhkScan.Overwrite = 1;
        fhkScan.SilentMode = false;
        /*ScanTo 扫描数据输出方式
         *0 – 文件(初始值)
         1 – DIB 句柄
         2 – 原始图像句柄
         本属性设置扫描仪读取的图像数据的输出目的地;
         当设置为“0 – 文件”时,图像数据输出至文件,参见 FileName 和 FileType 属性; 当设置为“1 – DIB 句柄”时,响应 ScanToDib 事件,获取 DIB 句柄;
         当设置为“2 – 原始图像句柄”时,响应 ScanToRaw 事件,获取图像内存句柄;
         * */
        fhkScan.ScanTo = 0;
        /*ScanCount 扫描纸张数目
         -1 或 1 – 32767(页数) 指定-1,扫描 ADF 上的所有纸张(初始值)
         *本属性仅在 PaperSupply 属性设置为“1 – ADF 正面”或“2 – ADF 双面”时有效;
         当 PaperSupply 属性设置为“0 – 平板”时,仅扫描一次;
         当本属性设置为 1,而 PaperSupply 属性设置为“2 – ADF 双面”时,仅扫描纸张的正面, 若要扫描双面,则本属性需要设置为 2;
         * */
        fhkScan.ScanCount = -1;
        /*DetectPageSize 检测纸张尺寸
         *0 – 不检测(初始值)
         1 – 页尾检测
         2 – 自动页面检测 3 – 黑色背景检测 4 – 自动纠偏
         用于选择扫描的页面检测模式;
         * */
        fhkScan.DetectPageSize = 2;
        fhkScan.SourceCurrentScan = false
      }
    //实时更新扫描文件
      function OnScanToFileEvent(scanFilePath)
      {
        var txtResults = document.getElementById("result");
        var str = txtResults.value;
        str += scanFilePath;
        str += "\r\n";
        txtResults.value = str;
      }

    </script>

然后在html中

<!--调用ActiveX控件-->
<object id="fhkScan" width="0" height="0" classid="clsid:******">
  </object>
  <!--记录扫描后的文件名及文件目录-->
  <input id="result" type="hidden" readonly="readonly" />
  <div id="app"></div>
   <!--扫描事件-->
  <script for="fhkScan" event="ScanToFile(scanFilePath)">
    OnScanToFileEvent(scanFilePath);
  </script>

然后是扫描按钮,使用的是Element-UI

<el-button type="danger" plain @click="scanDocument" >扫描
        </el-button>
scanDocument(){
    InitSettings(this.orderDocument,this.docList.length+1)
    //OpenScanner 初始化,获得扫描仪信息 应用程序在调用 StartScan 方法之前必须先调用本方法;
        // 返回值
        // 0 : RC_SUCCESS – 正常终止
        // 2 : RC_NOT_DS_FJTWAIN – 非 FUJITSU TWAIN 驱动
        // -1 : RC_FAILURE – 错误
        var rtn = fhkScan.OpenScanner(0)
        if (rtn == -1) {
          alert('打开扫描仪出错,错误代码为' + fhkScan.ErrorCode)
          return
        }
        /*StartScan ... 开始扫描
         返回值
         0 : RC_SUCCESS – 正常终止
         1 : RC_CANCEL – 用户取消或者发生导致设备无法继续扫描的错误(如内存不足等)
         -1 : RC_FAILURE – 错误
         *调用本方法之前,务必先调用 OpenScanner 开启扫描仪; 本方法执行结束以后,务必调用 CloseScanner 结束扫描;
         * */
        rtn = fhkScan.StartScan(0)
        if (rtn == -1) {
          fhkScan.CloseScanner(0)
          if (fhkScan.ErrorCode==1||fhkScan.ErrorCode==21) {
            alert('设备正在初始化,等待设备准备就绪后再重试')
          } else if (fhkScan.ErrorCode==2||fhkScan.ErrorCode==3||fhkScan.ErrorCode==5||fhkScan.ErrorCode==39||fhkScan.ErrorCode==40||fhkScan.ErrorCode==54){
            alert('请检查纸张,再重试')
          } else if (fhkScan.ErrorCode==4){
            alert('请关闭 ADF 盖板,再重试')
          } else if (fhkScan.ErrorCode==11){
            alert('设备可能被锁定,参照设备的用户指南')
          } else if (fhkScan.ErrorCode==15||fhkScan.ErrorCode==16||fhkScan.ErrorCode==17||fhkScan.ErrorCode==18||fhkScan.ErrorCode==19||fhkScan.ErrorCode==20){
            alert('非法操作或未知的设备问题,重启电脑和扫描仪设备再重试')
          }else if (fhkScan.ErrorCode==22||fhkScan.ErrorCode==44){
            alert('设备内置内存可能不足,请减小扫描图像尺寸再重试')
          }else if (fhkScan.ErrorCode==24||fhkScan.ErrorCode==25||fhkScan.ErrorCode==26||fhkScan.ErrorCode==27||fhkScan.ErrorCode==41||fhkScan.ErrorCode==43){
            alert('数据源错误,请检查驱动安装、设备电源或退出正在使用的应用程序')
          }else if (fhkScan.ErrorCode==29){
            alert('请检查设备是否正确连接并开启电源')
          }else if (fhkScan.ErrorCode==30){
            alert('指定了不支持的传送模式,修改 “ScanTo”属性再重试')
          }else if (fhkScan.ErrorCode==31){
            alert('指定了不支持的文件格式,修改 “FileType”属性再重试')
          } else if (fhkScan.ErrorCode==32){
            alert('请检查“FileName”属性指定的文件路径是否正确')
          } else if (fhkScan.ErrorCode==34||fhkScan.ErrorCode==36){
            alert('检查 TWAIN 驱动的版本')
          } else if (fhkScan.ErrorCode==35){
            alert('应用程序传递的窗口句柄无效,请检查窗口句柄是否正确')
          }else if (fhkScan.ErrorCode==37){
            alert('请确认设备是否支持 ADF 扫描,修改“PaperSupply”属性再重试')
          }else if (fhkScan.ErrorCode==42){
            alert('检测到取消或发生了使设备无法继续扫描的错误(如硬盘空间不足、内存不足等)')
          }else if (fhkScan.ErrorCode==45){
            alert('检查Z盘是否有足够的空间')
          }else if (fhkScan.ErrorCode==45||fhkScan.ErrorCode==46||fhkScan.ErrorCode==47||fhkScan.ErrorCode==48||fhkScan.ErrorCode==49||fhkScan.ErrorCode==50||fhkScan.ErrorCode==51){
            alert('检查“FileName”属性指定的文件路径')
          } else {
            alert('开始扫描出错,错误代码为 ' + fhkScan.ErrorCode)
          }
          fhkScan.CloseScanner(0)
        }
/*CloseScanner ... 关闭扫描仪
         *返回值
         0 : RC_SUCCESS – 正常终止 -1 : RC_FAILURE – 错误
         每当应用程序调用 OpenScanner 方法之后,都需要在结束前调用本方法;
         (本方法和 OpenScanner 方法必须成对调用)
         * */
        let result = fhkScan.CloseScanner(0)
        //扫描成功后将扫描到本地的文件上传到服务器
        if (result == 0&&rtn == 0) {
          this.uploadScanFile()
        }
}

后台写了个java包用来将扫描到本地的文件上传到服务器端,并记录下上传的文件列表

uploadToLocalServer (fileName) {
        return new Promise((resolve, reject) => {
          this.$http({
            url: 'http://127.0.0.1:520/localService/FTP?path=D:/scanImage/' + fileName,
            method: 'GET'
          }).then(res => {
            if (res.data.Code != 0) {
              this.fileLists = []
              this.$message.error(res.data.Message)
              return
            }
            let fileItem = res.data.Data[0]
            let obj = {
              fileName: fileItem.fileName,
              fileUrl: fileItem.filePath,
              type: 1
            }
            this.fileLists.push(obj)
            resolve(this.fileLists)
          }).catch(err => {
            this.fileLists = []
            console.warn(err)
          })
        })
      },
//将上传到服务器的文件列表与当前单据关联
      async uploadScanFile () {
        let files = (document.getElementById('result').value.split('\n')).slice(0, -1)
        let list = []
        if (files.length > 0) {
          files.forEach((item, index) => {
            let filePath = item.replace(/\\/g, '/')
            let filePathArr = filePath.split('/')
            let fileName = filePathArr[filePathArr.length - 1]
            list.push(this.uploadToLocalServer(fileName))
          })
        }
        await Promise.all(list)
        this.fileLists.forEach((paramsItem, paramsIndex) => {
          paramsItem.uid = paramsIndex
        })
        this.$http({
          url: this.util.getHost() + '/api/Trees/setDoc',
          method: 'post',
          data: {
            document: this..document,
            docList: this.fileLists
          }
        }).then(res => {
          if (res.data.code != 0) {
            this.$message.error(res.data.exceptionMsg)
            this.fileLists=[]
            return false
          } else {
            this.$message.success(`扫描成功`)
            document.getElementById('result').value = ''
            this.fileLists=[]
            this.$refs['conferenceList'].updateDoc()//调用接口更新数据
          }
        })
      },

这就完成了整个扫描过程,不过在使用过程中经常会遇到扫描仪报错(找不到数据源)的问题,需要重新启动扫描仪才可

Logo

前往低代码交流专区

更多推荐