如何用Deno将BMP图像文件转换为黑白Uint8Array?
在Deno中解析BMP并转换为黑白Uint8Array
要实现需求,需要先解析BMP文件的头信息,提取原始像素数据后再转换为你需要的黑白比特流格式。以下是具体实现方案:
核心思路
BMP文件由文件头、信息头和像素数据三部分组成:
- 从文件头获取像素数据的起始偏移量
- 从信息头获取图像宽高、位深度等关键参数
- 根据位深度处理像素数据:如果是1位黑白图直接提取并修正行顺序;如果是其他位深度(如24位彩色),先转灰度再按阈值生成黑白比特流,最后打包成Uint8Array
完整代码实现
async function processBmp(filePath) { const fileData = await Deno.readFile(filePath); const view = new DataView(fileData.buffer); // 解析BMP关键信息 const dataOffset = view.getUint32(10, true); // 像素数据起始位置 const width = view.getUint32(18, true); // 图像宽度 const height = view.getUint32(22, true); // 图像高度 const bitDepth = view.getUint16(28, true); // 位深度 // 处理1位黑白BMP(直接提取像素数据) if (bitDepth === 1) { const bytesPerRow = Math.ceil(width / 8); const reversedRows = []; // BMP像素行是倒序存储(从底部到顶部),反转后得到正确顺序 for (let i = height - 1; i >= 0; i--) { const start = dataOffset + i * bytesPerRow; reversedRows.push(fileData.slice(start, start + bytesPerRow)); } return new Uint8Array([].concat(...reversedRows.map(row => Array.from(row)))); } // 处理其他位深度(如24位彩色),转换为黑白比特流 const bytesPerPixel = bitDepth / 8; const bytesPerRow = Math.ceil((width * bytesPerPixel + 3) / 4) * 4; // BMP行对齐到4字节 const resultBytes = []; for (let y = height - 1; y >= 0; y--) { let currentByte = 0; let bitPos = 7; // 从字节的最高位开始填充 for (let x = 0; x < width; x++) { const pixelStart = dataOffset + y * bytesPerRow + x * bytesPerPixel; // 计算灰度值(采用加权公式更准确:0.299*R + 0.587*G + 0.114*B) const r = fileData[pixelStart + 2]; const g = fileData[pixelStart + 1]; const b = fileData[pixelStart]; const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b); // 阈值判断:灰度>127为白(1),否则为黑(0) const bit = gray > 127 ? 1 : 0; currentByte |= (bit << bitPos); bitPos--; // 填满一个字节或到行尾时,存入结果 if (bitPos < 0 || x === width - 1) { resultBytes.push(currentByte); currentByte = 0; bitPos = 7; } } } return new Uint8Array(resultBytes); } // 使用示例 const blackWhiteData = await processBmp('./path/to/my/image.bmp'); console.log(blackWhiteData); // 对应你示例中的[0x5A, 0x5A]
关键细节说明
- 行顺序修正:BMP的像素行是从图像底部开始存储的,所以需要反转行才能得到视觉上的正序
- 字节对齐:BMP的每行数据会对齐到4字节,处理非1位图像时必须考虑这一点,避免读取到补位的空字节
- 灰度转换:采用加权公式计算灰度比简单平均值更符合人眼对色彩的感知,你也可以根据需求调整阈值
内容的提问来源于stack exchange,提问作者Mqx
相关产品推荐
相关产品推荐

