vue 最佳实战-高拍仪集成(文件上传)

562 阅读2分钟
  1. 理清需求,明确要实现功能
  2. 查阅API文档,安装中间件
  3. 代码编写
  4. 功能完成

一、需求明确

  • 使用高拍仪摄像头进行拍照(数据采集)
  • 将采集的数据进行(预览、删除、合并)操作
  • 文件合并,将多个数据合并成pdf文件(进行上传)
  • 不合并,单文件展示(进行上传) 微信图片_20240731092803.png

二、中间件(启动)

作用:底层主要实现与客户端交互,读取文件信息,文件类型转换等。由集成商提供

三、代码编写

  1. 初始化容器,获取摄像头,获取分辨率,代码如下:
// 初始化摄像头
loadCameraDocument() {
    if (!window.WebSocket) {
        alert("浏览器不支持HTML5,请更新浏览器或者使用其它浏览器");
    }
    var obj = document.getElementById("CameraCtl");
    Cam_ControlInit(obj, 0, 0, 600, 400, (list,resolution)=> { 
    this.loading = false
    // 获取设备
    if (list?.length) { 
        this.deviceOptions=[]
        list.forEach((item,index) => { 
            this.deviceOptions.push({value:index,label:item})
        })
    }
    // 获取分辨率
    if (resolution?.length) { 
        this.resolutionOptions=[]
        resolution.forEach((item,index) => { 
        this.resolutionOptions.push({value:index,label:item})
        })
    }
    }, (msg)=> { 
        // 启动失败
        this.$message({
            showClose: true,
            message: msg||'设备开启失败,请重新尝试启动!',
            type: 'error'
        })
      this.loading = false
        this.noFindDevice=true
    });

},

//*************摄像头操作初始化***************
var initCallback
var faileCallback
function Cam_ControlInit(documentObj, mX, mY, mwidth, mheight, callback,failBack) {
    initCallback = callback
    faileCallback=failBack
    WebSocketConnect();                                 // 检测设备状态(心跳机制)
    InitCanvas(documentObj, mX, mY, mwidth, mheight);   // 渲染容器
    //console.log("Cam_ControlInit");
}


//*************获取设备数目***************
function Cam_GetDevCount() {
    GetDevCount();
}

//***************获取分辨率***************
var newSelectedIndex
function Cam_GetDevResolution(iCamNo) {
    newSelectedIndex = iCamNo
    GetResolution(iCamNo);
}
  1. 进行拍照,返回结果(base64),代码如下:
<el-button type="success" @click="toTakePhoto">拍照</el-button>

// 拍照
toTakePhoto() { 
    var name = this.formatDate(new Date().getTime());
    var selectedIndex=0
    var path;
    Cam_SetFileType(selectedIndex); //设置文件格式
    if (selectedIndex == 1) {
        path = "D:\\" + name + ".png";
    }
    else if (selectedIndex == 2) {
        path = "D:\\" + name + ".tif";
    }
    else if (selectedIndex == 3) {
        path = "D:\\" + name + ".pdf";
    }
    else {
        path = "D:\\" + name + ".jpg";
    }
    Cam_Photo(path, (src) => {
        this.imgsList.push({
        checked: true,
        src,
        fileName: name + ".jpg"
        })
    });  //主摄像头拍照
},

//*************拍照***************
 var newCallback
function Cam_Photo(fileAddr, callback) {
    newCallback=callback
      if (MainCamCutMode == 2) {
          var rectx, recty, rectw, recth;
          if (pALastX > pACurrentX)
              rectx = pACurrentX;
          else
              rectx = pALastX;
          if (pALastY > pACurrentY)
              recty = pACurrentY;
          else
              recty = pALastY;
          rectw = Math.abs(pACurrentX - pALastX);
          recth = Math.abs(pACurrentY - pALastY);

          SetCutRect(rectx, recty, rectw, recth);  //手动裁剪区域
      }    
     CaptureImage(fileAddr);
 }
 
 
 //拍照结果返回  base64Str 字符串
if (rDataArr[2] == 0x10) {
    var flag;
    if (rDataArr[3] == 0x01) {
        flag = 0;
        var imgpathLen = rDataArr[4] * 256 + rDataArr[5];
        if (imgpathLen == 0) {
            var base64Len = rDataArr[6] * 65536 + rDataArr[7] * 256 + rDataArr[8];
            var imgPathStr = "";
            var base64Data = new Uint8Array(base64Len);
            for (var i = 0; i < base64Len; i++) {
                base64Data[i] = rDataArr[9 + imgpathLen + i];
            }
            var base64Str = Uint8ArrayToString(base64Data);
            GetCaptrueImgResultCB(flag, imgPathStr, base64Str);
        }
        else {
            var base64Len = rDataArr[6] * 65536 + rDataArr[7] * 256 + rDataArr[8];
            var pData = new Uint8Array(imgpathLen);
            for (var i = 0; i < imgpathLen; i++) {
                pData[i] = rDataArr[9 + i];
            }
            var str = byteToString(pData);
            var imgPathStr = decodeURIComponent(str);

            var base64Data = new Uint8Array(base64Len);
            for (var i = 0; i < base64Len; i++) {
                base64Data[i] = rDataArr[9 + imgpathLen + i];
            }
            var base64Str = Uint8ArrayToString(base64Data);

            GetCaptrueImgResultCB(flag, imgPathStr, base64Str);
        }
    }
    if (rDataArr[3] == 0x02) {
        flag = 2;
        GetCaptrueImgResultCB(flag, "", "");
    }

}
  1. 文件删除,代码如下:
 // 删除文件
toDeleteFile(index, name) { 
    this.isDisabled = true
    this.$confirm('您确定要删除该文件, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
        }).then(() => {
            var path = `D:\\${name}`;
            this.imgsList.splice(index,1)
            DeleteFile(path);
            this.isDisabled = false
        }).catch(() => { 
            this.isDisabled = false
        });
},

function DeleteFile(filePath) {
    if (isSocketConnect) {
        if (filePath == "") {
            var packageCount = 1;
            var len = 0;
            var pindex = 0;
            var totalLen = 11;
            var aDataArray = new Uint8Array(totalLen);
            aDataArray[0] = 0x77;
            aDataArray[1] = 0x88;
            aDataArray[2] = 0xA8;
            aDataArray[3] = len >> 16 & 0xff;
            aDataArray[4] = len >> 8 & 0xff;
            aDataArray[5] = len & 0xff;
            aDataArray[6] = packageCount >> 8 & 0xff;   //包总数
            aDataArray[7] = packageCount & 0xff;   //包总数
            aDataArray[8] = 0;   //分包长度
            aDataArray[9] = pindex >> 8 & 0xff;   //包序号
            aDataArray[10] = pindex & 0xff;    //包序号
            console.log("pindex:" + pindex);
            socket.send(aDataArray.buffer);
        }
        else {
            var path = encodeURI(filePath);
            console.log(path);
            var pathArray = stringToByte(path);
            var len = pathArray.length;

            var packageCount = 0;
            var tmpLen = len;
            while (tmpLen > 0) {
                tmpLen = tmpLen - 90;
                packageCount++;
            }

            console.log("packageCount:" + packageCount);

            var pindex = 0;
            tmpLen = len;
            while (tmpLen > 0) {
                tmpLen = tmpLen - 90;

                if (tmpLen > 0) {
                    var totalLen = 90 + 11;
                    var aDataArray = new Uint8Array(totalLen);
                    aDataArray[0] = 0x77;
                    aDataArray[1] = 0x88;
                    aDataArray[2] = 0xA8;
                    aDataArray[3] = len >> 16 & 0xff;
                    aDataArray[4] = len >> 8 & 0xff;
                    aDataArray[5] = len & 0xff;
                    aDataArray[6] = packageCount >> 8 & 0xff;   //包总数
                    aDataArray[7] = packageCount & 0xff;   //包总数
                    aDataArray[8] = 90;   //分包长度
                    aDataArray[9] = pindex >> 8 & 0xff;   //包序号
                    aDataArray[10] = pindex & 0xff;    //包序号
                    console.log("pindex:" + pindex);
                    for (var i = 0; i < 90; i++) {
                        aDataArray[11 + i] = pathArray[i + pindex * 90];
                    }
                    socket.send(aDataArray.buffer);
                }
                else {
                    var totalLen = 90 + tmpLen + 11;  // 此时tmpLen为负数,做加法运算
                    var aDataArray = new Uint8Array(totalLen);
                    aDataArray[0] = 0x77;
                    aDataArray[1] = 0x88;
                    aDataArray[2] = 0xA8;
                    aDataArray[3] = len >> 16 & 0xff;
                    aDataArray[4] = len >> 8 & 0xff;
                    aDataArray[5] = len & 0xff;
                    aDataArray[6] = packageCount >> 8 & 0xff;   //包总数
                    aDataArray[7] = packageCount & 0xff;   //包总数
                    aDataArray[8] = 90 + tmpLen;   //分包长度
                    aDataArray[9] = pindex >> 8 & 0xff;   //包序号
                    aDataArray[10] = pindex & 0xff;    //包序号
                    console.log("pindex:" + pindex);
                    for (var i = 0; i < (90 + tmpLen); i++) {
                        aDataArray[11 + i] = pathArray[i + pindex * 90];
                    }
                    socket.send(aDataArray.buffer);
                }
                pindex++;
                toSleep(80);
            }
        }

    }
}
  • 4 .文件合并,代码如下:
// 合并为pdf(先添加,后合并)
toMergePDFFile() { 
    Cam_AddImgFileToPDF("");
    this.sleep(300);
    Cam_CombinePDF(`D:\\${this.generateRandomString(20)}.pdf`, (data) => { 
        base64Data = data
        fileName=`${this.generateRandomString(20)}.pdf`
        this.toHttpUploadFile()
    });

},
sleep(milliSeconds) {
    var startTime = new Date().getTime();
    while (new Date().getTime() < startTime + milliSeconds);
},
  • 5.其他功能,代码如下:
//对焦
toCamFocus() { 
    Cam_Focus()
},
//切换图像质量
toSetJpgQuality() {
    var val = this.imageQualityOptions[this.imageQuality].label;
    Cam_SetJpgQuality(val);
},
// 属性
toShowVideoProp() { 
    Cam_ShowVideoProp()
},
// 左旋转
toRotateLeft() { 
    Cam_RotateLeft()
},
// 右旋转
toRotateRight() { 
    Cam_RotateRight()
},
  • 6.文件上传
// 文件上传
toHttpUploadFile() { 
    filesList=[]
    UpladFile(base64Data, fileName, (data,file) => { 
        api.addFileRecord(data).then(res => { 
          const {fileName,address,id } = res.data
          this.submitLoading = false
          this.addDialogVisible=false
          filesList.push({
            name:fileName,
            url: address,
            id
          })
          fileIds.push(id)
          fileUrls.push(address)
          this.$emit('update',fileIds,fileUrls,filesList)
          api.uploadFile(res.data, file)
        })
    })

},
// base64转换为对应的文件类型
function dataURLtoFile(dataurl, filename) {
    var bstr = atob(dataurl);
    var n = bstr.length;
    var u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    var suffix = filename.substring(filename.length - 3, filename.length);
    if (suffix == "jpg" || suffix == "JPG")
        return new File([u8arr], filename, { type: 'image/jpg' });
    if (suffix == "png" || suffix == "PNG")
        return new File([u8arr], filename, { type: 'image/png' });
    if (suffix == "tif" || suffix == "TIF")
        return new File([u8arr], filename, { type: 'image/tiff' });
    if (suffix == "pdf" || suffix == "PDF")
        new File([u8arr], filename, { type: 'application/pdf' });
    return new File([u8arr], filename, { type: 'application/jpg' });
}
// 将文件转为FormData
 function UpladFile(base64data, fileName, callback) {
    //base64数据转为文件对象 
    var fileObj = dataURLtoFile(base64data, fileName); 
    var fm = document.forms[0];
    var form = new FormData(fm);
    const { name, size } = fileObj;
    form.append('fileName', name);
    form.append('size', size);
    console.log('文件信息'+JSON.stringify(fileObj))
    callback(form,fileObj);
}

四、功能完成

总结:

  • 在切换摄像头时、要重新获取对应摄像头的分辨率信息,否则设备会渲染失败
  • 文件上传,要将获取到的base64进行转换
  • 文件在上传时,要先处理合并逻辑,反之无法上传
  • 文件删除,文件路径要选择正确,反之无法删除本地文件