Bmp是什么?
BMP是英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式,能够被多种Windows应用程序所支持。随着Windows操作系统的流行与丰富的Windows应用程序的开发,BMP位图格式理所当然地被广泛应用。这种格式的特点是包含的图像信息较丰富,几乎不进行压缩,但由此导致了它与生俱来的缺点–占用磁盘空间过大。所以,目前BMP在单机上比较流行。(来自百度百科的粘贴)
Bmp图片说明
Bmp有2,4,8,16,24,32位图,24以上图位真彩色,位表示图片可生成的颜色
。8位图表示的是2的8次方也就是256种颜色。
bmp数据存贮
低地址存放低位数据,高地址存放高位数据
如果一个数据是0x1576
在bmp中应该是0x7515
Bmp组成(文件结构)
一个bmp文件组成由,文件头、位图信息头、彩色表、颜色数据
Bmp文件头
bfType; 2bytes 必须是bm 也就是 424d
bfSize; 4bytes 该文件的大小,用字节为单位(文件头,位图信息头,彩色表,颜色数据总和)
bfReserved1; 2bytes 保留 必须位0
bfReserved2; 2bytes 保留 必须位0
bfOffBits; 4bytes 偏移量 快速的读取数据
位图信息头
biSize; 4bytes 指定此结构体的长度
biWidth; 4bytes 图片的宽度
biHeight; 4bytes 图片的高度
biPlanes; 2bytes 平面数,为1
biBitCount; 2bytes 比特数 1/4/8/16/24/32
biCompression; 4bytes 说明图像的压缩类型 一般不压缩
biSizeImage; 4bytes 图像大小以字节微单问 因为时BI_RBG格式所以是0
biXPelsPerMeter;4bytes 水平分辨率,缺省
biYPelsPerMeter 4bytes 垂直分辨率,缺省
biClrUsed; 4bytes 说明位图实际使用的彩色表中的索引数 使用调色板则为0
biClrImportant; 4bytes 说明对图像显示有重要影响的颜色索引的数目, 0表示都重要
彩色表
颜色表对应的是0-255之间的数值,在八位图中颜色表应该是
00,00,00,00
01,01,01,00
.....
255,255,255,00
分别对应这 R(红),G(绿),B(蓝),A(透明度)这里默认为00
颜色数据
每一位的数值都应该0-255之间,
在八位图中,一个字节数据代表图像中的一个像素点,24位图,需要3个字节代表一个像素点(也就是将一个字节变成三个字节)。
代码实现
//利用opencv拿到24位图的数据
const cv = require('opencv4nodejs')
//读取数据
const img = cv.imread('1.bmp');
//转化为单通道也就是八位
const gary =img.cvtColor(cv.COLOR_BGR2GRAY)
//拿到数组
const garyARR =gary.getDataAsArray()
// bmp文件头(数据是经过计算并高低位调换过的最终数据)
const bfType = Buffer.from('424d',"hex")
const bfSize = Buffer.from('36040400',"hex")
const bfReserved1 = Buffer.from('0000',"hex")
const bfReserved2 = Buffer.from('0000',"hex")
const bfOffBits = Buffer.from('360400000',"hex")
const bmpFileTop =Buffer.concat([bfType,bfSize,bfReserved1,bfReserved2,bfOffBits])
//位图信息头(数据是经过计算并高低位调换过的最终数据)
const biSize = Buffer.from('28000000',"hex")
const biWidth = Buffer.from('00020000',"hex")
const biHeight = Buffer.from('00020000',"hex")
const biPlanes = Buffer.from('0100',"hex")
const biBitCount = Buffer.from('0800',"hex")
const biCompression = Buffer.from('00000000',"hex")
const biSizeImage = Buffer.from('00000000',"hex")
const biXPelsPerMeter = Buffer.from('00000000',"hex")
const biYPelsPerMeter = Buffer.from('00000000',"hex")
const biClrUsed = Buffer.from('00000000',"hex")
const biClrImportant = Buffer.from('00000000',"hex")
const bmpInfoTop =Buffer.concat([biSize,biWidth,biHeight,biPlanes,biBitCount,biCompression,biSizeImage,biXPelsPerMeter
,biYPelsPerMeter,biClrUsed,biClrImportant])
//颜色表 8位图位2的八次方所以是 256
const RBGbuf = Buffer.alloc(256*4)
for (let i = 0; i < 256; i++) {
let hexia = i.toString(16)
if (hexia.length == 1) {
hexia = '0x0' + hexia
}else {
hexia ='0x'+hexia
}
RBGbuf[0 + 4 * i]= hexia
RBGbuf[1 + 4 * i]= hexia
RBGbuf[2 + 4 * i]= hexia
RBGbuf[3 + 4 * i]= '00'
}
//需要读取数据 从后往前读取才正确
let len = garyARR.length-1;
let str ='';
for (let i = len; i >= 0; i--) {
let inlen = garyARR[i].length;
for (let j = 0; j < inlen; j++) {
let strhex =garyARR[i][j].toString(16);
if(strhex.length==1){
strhex='0'+strhex
}
str +=strhex
}
}
const data = Buffer.from(str,"hex")
//拼接
const enddata = Buffer.concat([bmpFileTop,bmpInfoTop,RBGbuf,data])
const fs = require('fs')
fs.writeFileSync('fsw1.bmp',enddata)
最终查看图片的属性(数据大小变成原来的三分之一)
最后附赠一篇更详细的bmp格式说明,点击跳转,和一篇java代码相关代码。