vue2将png格式图片转为bmp格式并导入喷码枪中使用

vue2将png格式图片转为bmp格式并导入喷码枪中使用

技术要点
1.格式转换: 将PNG格式转换为BMP格式,提高与喷码枪的兼容性
2.二进制处理: 使用DataView和ArrayBuffer直接操作二进制数据构建BMP文件
3.内存管理: 正确释放创建的对象URL避免内存泄漏
4.错误处理: 包含完整的错误处理机制
这样的实现能够生成标准的BMP格式文件,解决了喷码枪无法识别文件的问题。

 // 导出操作 - 修改为下载BMP格式图片
    handleExportPrint() {
      let barcodeParams = {
        bussinessId: this.parentData.proWorkorderDetailId,
        bussinessCode: this.parentData.prodSeriaNo,
        barcodeType: "PSN2D",
      };
      getBarcodeUrl(barcodeParams).then((response) => {
        if (response.data != null) {
          const barcodeUrl = response.data.barcodeUrl;
          const barcodeContent = response.data.barcodeContent; // 获取条码内容用于文件命名
          if (barcodeUrl) {
            // 使用修改后的函数
            this.pngToBmpCanvas(barcodeUrl, barcodeContent);
          } else {
            this.$message.error("暂没有生成条喷码");
          }
        }
      });
    },

    /**
     * 使用Canvas将PNG转换为BMP格式并触发下载
     * @param {string} pngUrl - PNG图片URL
     * @param {string} filename - 文件名
     */
    pngToBmpCanvas(pngUrl, filename) {
      const img = new Image();
      img.crossOrigin = "anonymous";
      img.src = pngUrl;

      img.onload = () => {
        const canvas = document.createElement("canvas");
        const ctx = canvas.getContext("2d");

        canvas.width = img.width;
        canvas.height = img.height;

        // 绘制图像到canvas
        ctx.drawImage(img, 0, 0);

        // 获取图像数据
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

        // 创建BMP数据
        const bmpData = this.createBMPData(imageData, false);
        const blob = new Blob([bmpData], { type: "image/bmp" });

        // 创建下载链接并触发下载
        const url = window.URL.createObjectURL(blob);
        const link = document.createElement("a");
        link.href = url;
        link.download = `${filename || "barcode"}.bmp`;

        // 触发下载
        document.body.appendChild(link);
        link.click();

        // 清理
        document.body.removeChild(link);
        window.URL.revokeObjectURL(url);
      };

      img.onerror = (error) => {
        console.error("图片加载失败:", error);
        this.$message.error("图片加载失败");
      };
    },

    /**
     * 创建BMP文件数据
     * @param {ImageData} imageData - Canvas图像数据
     * @param {boolean} withAlpha - 是否包含Alpha通道
     * @returns {ArrayBuffer} BMP文件数据
     */
    createBMPData(imageData, withAlpha = false) {
      const width = imageData.width;
      const height = imageData.height;
      const data = imageData.data;

      // 计算每行字节数(必须是4的倍数)
      const bytesPerPixel = withAlpha ? 4 : 3;
      const rowSize = Math.ceil((width * bytesPerPixel) / 4) * 4;
      const pixelArraySize = rowSize * height;

      // BMP文件头(14字节)
      const fileHeaderSize = 14;
      const infoHeaderSize = 40;
      const fileSize = fileHeaderSize + infoHeaderSize + pixelArraySize;

      const buffer = new ArrayBuffer(fileSize);
      const view = new DataView(buffer);

      let offset = 0;

      // 文件头
      view.setUint8(offset++, 0x42); // 'B'
      view.setUint8(offset++, 0x4d); // 'M'
      view.setUint32(offset, fileSize, true);
      offset += 4; // 文件大小
      view.setUint32(offset, 0, true);
      offset += 4; // 保留字段
      view.setUint32(offset, fileHeaderSize + infoHeaderSize, true);
      offset += 4; // 像素数据偏移

      // 信息头
      view.setUint32(offset, infoHeaderSize, true);
      offset += 4; // 信息头大小
      view.setInt32(offset, width, true);
      offset += 4; // 宽度
      view.setInt32(offset, height, true);
      offset += 4; // 高度
      view.setUint16(offset, 1, true);
      offset += 2; // 颜色平面数
      view.setUint16(offset, withAlpha ? 32 : 24, true);
      offset += 2; // 每像素位数
      view.setUint32(offset, 0, true);
      offset += 4; // 压缩方式(0=不压缩)
      view.setUint32(offset, pixelArraySize, true);
      offset += 4; // 图像数据大小
      view.setInt32(offset, 2835, true);
      offset += 4; // 水平分辨率(像素/米)
      view.setInt32(offset, 2835, true);
      offset += 4; // 垂直分辨率
      view.setUint32(offset, 0, true);
      offset += 4; // 使用的颜色数
      view.setUint32(offset, 0, true);
      offset += 4; // 重要颜色数

      // 像素数据(BMP是从下到上存储)
      for (let y = height - 1; y >= 0; y--) {
        for (let x = 0; x < width; x++) {
          const index = (y * width + x) * 4;
          const r = data[index];
          const g = data[index + 1];
          const b = data[index + 2];
          const a = data[index + 3];

          if (withAlpha) {
            // BGRA格式(带Alpha)
            view.setUint8(offset++, b);
            view.setUint8(offset++, g);
            view.setUint8(offset++, r);
            view.setUint8(offset++, a);
          } else {
            // BGR格式(无Alpha)
            view.setUint8(offset++, b);
            view.setUint8(offset++, g);
            view.setUint8(offset++, r);
          }
        }

        // 行对齐填充
        const padding = rowSize - width * bytesPerPixel;
        for (let i = 0; i < padding; i++) {
          view.setUint8(offset++, 0);
        }
      }

      return buffer;
    },
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值