BMP文件解析
BMP文件主要有四部分组成,位图头、位图信息、调色板、位图数据。
位图头
保存文件的总体信息
字节 #0-1 保存位图文件的标识符,用于标识BMP和DIB文件的魔数,一般为0x42 0x4D,即ASCII的BM。以下为可能的取值:
BM – Windows 3.1x, 95, NT, … etc.
BA – OS/2 struct Bitmap Array
CI – OS/2 struct Color Icon
CP – OS/2 const Color Pointer
IC – OS/2 struct Icon
PT – OS/2 Pointer
字节 #2-5 使用一个dword保存位图文件大小。
字节 #6-9 是保留部分,留做以后的扩展使用,对实际的解码格式没有影响。
字节 #10-13 保存位图数据位置的地址偏移,也就是起始地址。
位图信息
这部分告诉应用程序图像的详细信息,在屏幕上显示图像将会使用这些信息
字节 #14-17 定义以下用来描述影像的区块(BitmapInfoHeader)的大小。
字节 #18-21 保存位图宽度(以像素个数表示)。
字节 #22-25 保存位图高度(以像素个数表示)。
字节 #26-27 保存所用彩色位面的个数。不经常使用。
字节 #28-29 保存每个像素的位数,它是图像的颜色深度。常用值是1、4、8(灰阶)和24(彩色)。
字节 #30-33 定义所用的压缩算法。允许的值是0、1、2、3、4、5。
0 - 没有压缩(也用BI_RGB表示)
1 - 行程长度编码 8位/像素(也用BI_RLE8表示)
2 - 行程长度编码4位/像素(也用BI_RLE4表示)
3 - Bit field(也用BI_BITFIELDS表示)
4 - JPEG图像(也用BI_JPEG表示)
5 - PNG图像(也用BI_PNG表示)
调色板
暂时不做介绍
位图数据
在典型的24位位图下,一个像素由24bit,即3个字节(R\G\B)组成。
程序实现
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include<windows.h>
#include"bmp2yuv.h"
BITMAPFILEHEADER File_header;
BITMAPINFOHEADER Info_header;
if(fread(&File_header,sizeof(BITMAPFILEHEADER),1,bmpFile)!=1)
{
printf("read file header error!\n");
exit(0);
}
if(File_header.bfType!=0x4D42)
{
printf("Not bmp file!\n");
exit(0);
}
else
{
printf("This is a bmp file!\n");
}
if(fread(&Info_header,sizeof(BITMAPINFOHEADER),1,bmpFile)!=1)
{
printf("read info header error!\n");
exit(0);
}
frameWidth = Info_header.biWidth;
frameHeight = Info_header.biHeight;
bmpBuf = (unsigned char*)malloc(frameWidth * frameHeight * 4);
yBuf = (unsigned char*)malloc(frameWidth * frameHeight);
uBuf = (unsigned char*)malloc((frameWidth * frameHeight) / 4);
vBuf = (unsigned char*)malloc((frameWidth * frameHeight) / 4);
if (bmpBuf == NULL || yBuf == NULL || uBuf == NULL || vBuf == NULL)
{
printf("no enought memory\n");
exit(1);
}
if(fread(bmpBuf, 1, frameWidth * frameHeight * 4, bmpFile)==NULL)
{
printf("read data error!\n");
exit(1);
}
for (int i = 0; i < frameWidth*frameHeight; i++)
{
if (yBuf[i] < 16) yBuf[i] = 16;
if (yBuf[i] > 235) yBuf[i] = 235;
}
for (int i = 0; i < frameWidth*frameHeight/4; i++)
{
if (uBuf[i] < 16) uBuf[i] = 16;
if (uBuf[i] > 240) uBuf[i] = 240;
if (vBuf[i] < 16) vBuf[i] = 16;
if (vBuf[i] > 240) vBuf[i] = 240;
}
for (int i = 0; i < 40; i++)
{
fwrite(yBuf, 1, frameWidth * frameHeight, yuvFile);
fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
}
实验结果验证
处理后: