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;
},

被折叠的 条评论
为什么被折叠?



