#include<stdio.h>
#include<stdlib.h>
#include<math.h>

typedef unsigned short int WORD;
typedef unsigned int DWORD;
typedef int LONG;
typedef unsigned char BYTE;

/*********** *********** *********** *********** *********** *********** ***********
* definition :struct
* Description :位图文件头
*********** *********** *********** *********** *********** *********** ***********/
#pragma pack(1)/////////////////将结构体中成员按n字节对齐
typedef struct tagBITMAPFILEHEADER
{
    WORD bfType;////////////////文件类型,必须为BM
    DWORD bfSize;///////////////指定文件大小,以字节为单位(3-6字节,低位在前)
    WORD bfReserved1;///////////文件保留字,必须为0
    WORD bfReserved2;///////////文件保留字,必须为0
    DWORD bfOffBits;////////////从文件头到实际位图数据的偏移字节数(11-14字节,低位在前)
}BITMAPFILEHEADER;
/*********** *********** *********** *********** *********** *********** ***********
* definition :struct
* Description :位图信息头
*********** *********** *********** *********** *********** *********** ***********/
typedef struct tagBITMAPINFOHEADER
{
	DWORD biSize;///////////////本结构所占用字节数,为40。注意:实际操作中则有44,这是字节补齐的原因
	LONG biWidth;///////////////位图的宽度,以像素为单位
	LONG biHeight;//////////////位图的高度,以像素为单位
	WORD biPlanes;//////////////目标设备的级别,必须为1
	WORD biBitCount;////////////每个像素所需的位数,1(双色),4(16色),8(256色)16(高彩色),24(真彩色)或32之一
	DWORD biCompression;////////位图压缩类型,0(不压缩),1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
	DWORD biSizeImage;//////////位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位
	LONG biXPelsPerMeter;///////位图水平分辨率,每米像素数
	LONG biYPelsPerMeter;///////位图垂直分辨率,每米像素数
	DWORD biClrUsed;////////////位图实际使用的颜色表中的颜色数,若该值为0,则使用颜色数为2的biBitCount次方
	DWORD biClrImportant;///////位图显示过程中重要的颜色数,若该值为0,则所有的颜色都重要
}BITMAPINFOHEADER;
#pragma pack()//////////////////取消自定义字节方式
/*********** *********** *********** *********** *********** *********** ***********
* definition :struct
* Description :调色板
*********** *********** *********** *********** *********** *********** ***********/
typedef struct tagRGBQUAD
{
	BYTE rgbBlue;///////////////蓝色的亮度(0-255)
	BYTE rgbGreen;//////////////绿色的亮度(0-255)
	BYTE rgbRed;////////////////红色的亮度(0-255)
	BYTE rgbReserved;///////////保留,必须为0
}RGBQUAD;
/*********** *********** *********** *********** *********** *********** ***********
* Function Name :printInfo
* Description :输出文件信息
*********** *********** *********** *********** *********** *********** ***********/
void printInfo(BITMAPFILEHEADER fileHeader,BITMAPINFOHEADER infoHeader)
{
	printf("\n\n\tThe information of your map:\n");
	printf("\t----------------------------------------------\n");

	printf("\tbfOffBits:\t%d\n",fileHeader.bfOffBits);
	printf("\tbfSize:\t\t%d\n\n",fileHeader.bfSize);

	printf("\tbiBitCount:\t%d\n",infoHeader.biBitCount);
	printf("\tbiHeight:\t%d\n",infoHeader.biHeight);
	printf("\tbiWidth:\t%d\n",infoHeader.biWidth);
	printf("\tbiSize:\t\t%d\n",infoHeader.biSize);
	printf("\tbiClrUsed:\t%d\n\n\n",infoHeader.biClrUsed);
}
/*********** *********** *********** *********** *********** *********** ***********
* Function Name :printInfo
* Description :输出画板信息
*********** *********** *********** *********** *********** *********** ***********/
void printPalette(RGBQUAD *rgbPalette,int sizeOfPalette)
{
	int i;

	printf("\tThe Palette of your map:\n");
	printf("\t----------------------------------------------\n");
	for(i=0;i<sizeOfPalette;i++)
	{
		printf("\t%d/%d:",i+1,sizeOfPalette);
		printf("\trgbBlue=%d\t",(rgbPalette+i)->rgbBlue);
		printf("\trgbGreen=%d\t",(rgbPalette+i)->rgbGreen);
		printf("\trgbRed=%d\n",(rgbPalette+i)->rgbRed);
	}
	printf("\n\n\n");
}


bool ReadBmp(BITMAPFILEHEADER &fileHeader,BITMAPINFOHEADER &infoHeader,RGBQUAD *&rgbPalette/*给它去别名一起变化*/,void *img[5000],char *FileName)
{
	FILE *fpIn=fopen(FileName,"rb");
	int i=0,sizeOfHang=0,sizeOfPalette=0;

	if(fpIn==NULL)
		return false;

	fread(&fileHeader,sizeof(BITMAPFILEHEADER),1,fpIn);
	fread(&infoHeader,sizeof(BITMAPINFOHEADER),1,fpIn);

	if(infoHeader.biBitCount<16)
	{
		sizeOfPalette=int( pow(2,infoHeader.biBitCount) );
		rgbPalette=new RGBQUAD[sizeOfPalette];

		fread(rgbPalette,sizeof(RGBQUAD),sizeOfPalette,fpIn);
	}


	if( (infoHeader.biBitCount * infoHeader.biWidth)%32==0)
		sizeOfHang=(infoHeader.biBitCount * infoHeader.biWidth)/8;
	else
		sizeOfHang=((infoHeader.biBitCount * infoHeader.biWidth)/32+1)*4;

	for(i=0;i<infoHeader.biHeight;i++)
	{
		img[i]=(void *) new BYTE[sizeOfHang];
		fread(img[i],sizeOfHang,1,fpIn);
	}

	fclose(fpIn);
	return true;
}


void SaveBmp(BITMAPFILEHEADER &fileHeader,BITMAPINFOHEADER &infoHeader,RGBQUAD *rgbPalette,void *img[5000],char *FileName)
{
	FILE *fpOut=fopen(FileName,"wb");
	int i=0,sizeOfHang=0,sizeOfPalette=0;

	fwrite(&fileHeader,sizeof(BITMAPFILEHEADER),1,fpOut);
	fwrite(&infoHeader,sizeof(BITMAPINFOHEADER),1,fpOut);

	if(infoHeader.biBitCount<16)
	{
		sizeOfPalette=int( pow(2,infoHeader.biBitCount) );
		fwrite(rgbPalette,sizeof(RGBQUAD),sizeOfPalette,fpOut);
	}


	if( (infoHeader.biBitCount * infoHeader.biWidth)%32==0)
		sizeOfHang=(infoHeader.biBitCount * infoHeader.biWidth)/8;
	else
		sizeOfHang=((infoHeader.biBitCount * infoHeader.biWidth)/32+1)*4;

	for(i=0;i<infoHeader.biHeight;i++)
		fwrite(img[i],sizeOfHang,1,fpOut);

	fclose(fpOut);	
}


void main()
{
	BITMAPFILEHEADER fileHeader;
	BITMAPINFOHEADER infoHeader;
	RGBQUAD *rgbPalette;//调色板
	void * img[5000];
	char *FileName="E:\\1.bmp";

	ReadBmp(fileHeader,infoHeader,rgbPalette,img,FileName);
	SaveBmp(fileHeader,infoHeader,rgbPalette,img,"E:\\2.bmp");

}