世界杯举办地_世界杯预选赛巴西 - emsxbc.com

图像基础:BMP、RGB、JPG、PNG等格式详解(一)

什么是BMP

BMP是英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式,能够被多种Windows应用程序所支持。随着Windows操作系统的流行与丰富的Windows应用程序的开发,BMP位图格式理所当然地被广泛应用。这种格式的特点是包含的图像信息较丰富,几乎不进行压缩,但由此导致了它与生俱生来的缺点–占用磁盘空间过大。所以,目前BMP在单机上比较流行。

BMP文件结构

BMP文件由4部分组成: 1.位图文件头(bitmap-file header)(大小为14Byte) 2.位图信息头(bitmap-informationheader)(大小为40Byte) 3.颜色表(color table) 4.颜色点阵数据(bits data) (24位真彩色位图没有颜色表,所以只有1、2、4这三部分。)

示例如下图:

BMP常见参数

色彩深度又叫色彩位数,即位图中要用多少个二进制位来表示每个点的颜色,是分辨率的一个重要指标。常用有1位(单色),2位(4色,CGA),4位(16色,VGA),8位(256色),16位(增强色),24位和32位(真彩色)等。 BMP文件记录一行图像是以字节为单位的。因此,就不存在一个字节中的数据位信息表示的点在不同的两行中。也就是说,设显示模式位16色,在每个字节分配两个点信息时,如果图像的宽度位奇数,那么最后一个像素点的信息将独占一个字节,这个字节的后4位将没有意义。接下来的一个字节将开始记录下一行的信息。 为了显示的方便,除了真彩色外,其他的每种颜色模式的行字节数要用数据“00”补齐为4的整数倍。如果显示模式为16色(2个字节),当图像宽为19时,存储时每行则要补充4-(19/2+1)%4=2个字节。如果显示模式为256色,当图像宽为19时,每行也要补充4-19%4=1个字节。

位图行四字节对齐算法: 第一种表示方法: LineByte = [(biWidth * biBitCount + 7) / 8 +3 ])/ 4 * 4 第二种表示方法: LineByte = (biWidth * biBitCount + 31) /32 *4

LineByte :每行所占的字节 biWidth : 图片像素宽度 biBitCount :像素深度,1bit,4bit,8bit… biWidth * biBitCount :未填充时一行数据所占的位数 (biWidth * biBitCount+7) / 8 :未对齐时一行数据所占的字节数 [(biWidth * biBitCount + 7) / 8 +3 ])/ 4 :对齐时一行数据所占的字节单元(4Byte)数 (biWidth * biBitCount + 31) /32 :对齐时一行数据所占的字节单元(4Byte)数

BMP文件大小计算

1色黑白: 文件头(14字节) + 信息头(40字节) + 2个调色板(共8字节) + Height(图像高度) * (Width + 8 - Width % 8) / 8

16色: 文件头(14字节) + 信息头(40字节) + 16个调色板(共64字节) + Height(图像高度) * (Width + 4 - Width % 4) / 2

256色: 文件头(14字节) + 信息头(40字节) + 256个调色板(共1024字节) + Height(图像高度) * (Width + 4 - Width % 4)

16位色: 文件头(14字节) + 信息头(40字节) + Height(图像高度) * (Width + 4 - Width % 4) * 2 (由于每个像素由两个字节表示)

24位色: 文件头(14字节) + 信息头(40字节) + Height(图像高度) * (Width + 4 - Width % 4) * 3 (由于每个像素由三个字节表示)

BMP颜色点阵数据

1、RGB数据也是倒着念的,原始数据是按B、G、R的顺序排列的。 2、位图全部的像素,是按照自下向上,自左向右的顺序排列的。 即:BMP内存第0行,是真实图像下面的最后一行。 举例,假如图像为2*2大小,像素三颜色按照RGB的顺序, 我们看到的图像为: 1 2 3, 11 22 33 4 5 6, 44 55 66

内存表示如下: 6 5 4, 66 55 44 (0 0) – 第0行 3 2 1, 33 22 11 (0 0) – 第1行 注意,通常内存是需要内存对齐的,所以每行后面可能会有对齐所产生的0.

BMP相关代码

读取BMP头文件信息

#include

#include

typedef struct tagBITMAPFILEHEADER

{

unsigned short int bfType; //位图文件的类型,必须为BM

unsigned long bfSize; //文件大小,以字节为单位

unsigned short int bfReserverd1; //位图文件保留字,必须为0

unsigned short int bfReserverd2; //位图文件保留字,必须为0

unsigned long bfbfOffBits; //位图文件头到数据的偏移量,以字节为单位

}BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER

{

long biSize; //该结构大小,字节为单位

long biWidth; //图形宽度以象素为单位

long biHeight; //图形高度以象素为单位

short int biPlanes; //目标设备的级别,必须为1

short int biBitcount; //颜色深度,每个象素所需要的位数

short int biCompression; //位图的压缩类型

long biSizeImage; //位图的大小,以字节为单位

long biXPelsPermeter; //位图水平分辨率,每米像素数

long biYPelsPermeter; //位图垂直分辨率,每米像素数

long biClrUsed; //位图实际使用的颜色表中的颜色数

long biClrImportant; //位图显示过程中重要的颜色数

}BITMAPINFOHEADER;

typedef struct

{

BITMAPFILEHEADER file; //文件信息区

BITMAPINFOHEADER info; //图象信息区

}bmp;

bmp readbmpfile(void); //函数声明

int main(void){

bmp m; //定义一个结构变量

m=readbmpfile(); //读取一个位图

getchar();

return 0;

}

bmp readbmpfile(void) {

bmp m; //定义一个位图结构

FILE *fp;

if((fp=fopen( "d:\\1.bmp", "r"))==NULL)

{ printf( "can't open the bmp imgae.\n ");

exit(0);

}

else

{

fread(&m.file.bfType,sizeof(char),1,fp);

printf("类型为%c",m.file.bfType);

fread(&m.file.bfType,sizeof(char),1,fp);

printf("%c\n",m.file.bfType);

fread(&m.file.bfSize,sizeof(long),1,fp);

printf("文件长度为%d\n",m.file.bfSize);

fread(&m.file.bfReserverd1,sizeof(short int),1,fp);

printf("保留字1为%d\n",m.file.bfReserverd1);

fread(&m.file.bfReserverd2,sizeof(short int),1,fp);

printf("保留字2为%d\n",m.file.bfReserverd2);

fread(&m.file.bfbfOffBits,sizeof(long),1,fp);

printf("偏移量为%d\n",m.file.bfbfOffBits);

fread(&m.info.biSize,sizeof(long),1,fp);

printf("此结构大小为%d\n",m.info.biSize);

fread(&m.info.biWidth,sizeof(long),1,fp);

printf("位图的宽度为%d\n",m.info.biWidth);

fread(&m.info.biHeight,sizeof(long),1,fp);

printf("位图的高度为%d\n",m.info.biHeight);

fread(&m.info.biPlanes,sizeof(short),1,fp);

printf("目标设备位图数%d\n",m.info.biPlanes);

fread(&m.info.biBitcount,sizeof(short),1,fp);

printf("颜色深度为%d\n",m.info.biBitcount);

fread(&m.info.biCompression,sizeof(long),1,fp);

printf("位图压缩类型%d\n",m.info.biCompression);

fread(&m.info.biSizeImage,sizeof(long),1,fp);

printf("位图大小%d\n",m.info.biSizeImage);

fread(&m.info.biXPelsPermeter,sizeof(long),1,fp);

printf("位图水平分辨率为%d\n",m.info.biXPelsPermeter);

fread(&m.info.biYPelsPermeter,sizeof(long),1,fp);

printf("位图垂直分辨率为%d\n",m.info.biYPelsPermeter);

fread(&m.info.biClrUsed,sizeof(long),1,fp);

printf("位图实际使用颜色数%d\n",m.info.biClrUsed);

fread(&m.info.biClrImportant,sizeof(long),1,fp);

printf("位图显示中比较重要颜色数%d\n",m.info.biClrImportant);

}

return m;

}

BMP 32位色深转换24位色深

// transform 32-bit bitmap format to 24-bit bitmap format

void Bmp32ToBmp24(char Filename[])

{

char Filename2[] = "output.bmp";

//注意:如果没有LR_CREATEDIBSECTION,位图颜色将被映射到屏幕DC颜色

//也就是说,如果屏幕是16位颜色,则所有的图像都将映射到16位颜色

HBITMAP hbmp32 = (HBITMAP) LoadImage(NULL, Filename,

IMAGE_BITMAP, 0, 0,

LR_LOADFROMFILE |

LR_CREATEDIBSECTION);

BITMAP bmp;//获取位图信息

GetObject(hbmp32, sizeof(BITMAP), &bmp);

printf("Image Bit Depth : %dnWidth : %d , Height : %d n",

bmp.bmBitsPixel, bmp.bmWidth, bmp.bmHeight);//显示位图颜色模式和图像宽高

//计算24位图像每行的字节数

int BytesPerLine = 3 * bmp.bmWidth;

while(BytesPerLine % 4 != 0)

BytesPerLine ++;

BITMAPINFOHEADER bih = {0};//位图信息头

bih.biBitCount = 24;//每个像素字节大小

bih.biCompression = BI_RGB;

bih.biHeight = bmp.bmHeight;//高度

bih.biPlanes = 1;

bih.biSize = sizeof(BITMAPINFOHEADER);

bih.biSizeImage = BytesPerLine * bmp.bmHeight;//图像数据大小

bih.biWidth = bmp.bmWidth;//宽度

BITMAPFILEHEADER bfh = {0};//位图文件头

bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);//到位图数据的偏移量

bfh.bfSize = bfh.bfOffBits + bih.biSizeImage;//文件总的大小

bfh.bfType = (WORD)0x4d42;

FILE *fp = fopen(Filename2, "w+b");

fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);//写入位图文件头

fwrite(&bih, 1, sizeof(BITMAPINFOHEADER), fp);//写入位图信息头

byte * p = new byte[bih.biSizeImage];

//获取当前32位图像数据

GetDIBits(GetDC(NULL), hbmp32, 0, bmp.bmHeight, p, (LPBITMAPINFO)&bih, DIB_RGB_COLORS);

//只取rgb值,存入文件

byte b = 0;//用于填充

for(int i = 0 ; i < bmp.bmWidth * bmp.bmHeight ; i ++)

{

//32位位图图像的格式为:Blue, Green, Red, Alpha

fwrite(&(p[i * 3]), 1, 3, fp);

if(i % bmp.bmWidth == bmp.bmWidth - 1)//填充字节

{

for(int k = 0 ; k < (BytesPerLine - bmp.bmWidth * 3) ; k ++)

fwrite(&b, sizeof(byte), 1, fp);

}

}

delete [] p;

fclose(fp);

DeleteObject(hbmp32);

}