BMP文件旋转

来源:互联网 发布:mac装双系统好吗 编辑:程序博客网 时间:2024/04/29 06:16

//一、要求将bmp文件顺时针旋转90°,要求熟悉BMP的文件格式及熟悉文件操作//解题思路如下://1.BMP文件的组成此处不赘述,关键针对24位真彩图//文件头组成class Header//文件头{public:WORD bftype;//位图文件的类型,必须为“BM”DWORD bfsize;//位图文件大小,以字节为单位,整个文件,包括位图与文件头和信息头WORD bfReserved1;//位图文件保留字,必须为0WORD bfReserved2;//位图文件保留字,必须为0DWORD bfOffBits;//位图数据的起始位置,以相对于位图文件头的偏移量表示,以字节为单位};/其中WORD等为自定义数据类型以配合文档说typedef unsigned char BYTE;//BYTE为每个像素的RGB类,数值在0~255typedef unsigned int DWORD;//四个字节typedef unsigned short WORD;//两个字节typedef long LONG;//四个字节信息头组成class Info//信息头{public:DWORD biSize;//本类所用的字节数LONG biWidth;//位图的宽度,以像素为单位LONG biHeight;//位图的高度,以像素为单位WORD biPlanes;//目标设备的平面数//不清,必须为1//什么WORD biBitCount;//每个像素所需的位数,必须是1(双色),4(16色),8(256色)或24(真彩色)之一DWORD biCompression;//位图压缩类型,必须是 0(不压缩),1(BI_RLE8压缩类型)或 2(BI_RLE4压缩类型)之一DWORD biSizeImage;//位图的大小,以字节为单位LONG biXPelsPerMeter;//位图水平分辨率,每米像素数LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数DWORD biClrUsed;//位图实际使用的颜色表中的颜色数DWORD biClrImportant;//位图显示过程中重要的颜色数};这说明bmp高H,宽W,每个坐标下(x,y)有一个像素,其中像素有3个字节,分别为RGB读写文件int main(int argc,char* argv[]){char* src_name;char* dest_name;if(argc == 1){cout<<"use \"src.bmp\" as default input file name,use \"dest.bmp\" as default output file name\n";src_name = new char[10];dest_name = new char[10];strcpy(src_name,"src.bmp");strcpy(dest_name,"dest.bmp");}else{src_name = argv[1];dest_name = argv[2];}Header fileHeader;Info infoHeader;ifstream infile(src_name,ios::in|ios::binary);if(!infile){cout<<"读取文件失败"<<endl;return 0;}ofstream outfile(dest_name,ios::out|ios::binary);infile.read((char*) &fileHeader,sizeof(Header));infile.read((char*) &infoHeader,sizeof(Info));if(infoHeader.biBitCount == 24)Trans<RGB24>(infile,outfile,fileHeader,infoHeader);elseTrans<RGB36>(infile,outfile,fileHeader,infoHeader);return 0;}//首先将src.bmp的文件头和信息头读入到内存的fileHeader 和infoHeader位置//然后再进行旋转操作函数//旋转函数的编写//首先要改变目标函数的文件头数据和信息头数据,这里主要是文件头的bfSize即位图文件的大小和信息头的biWidth \biHeight\ biSizeImage//其次要进行旋转操作,即改变位图旋转90°后的数据存储//所以要先读入位图数据//考虑到//Windows 规定图像文件中一个扫描行所占的字节数必须是 4 的倍数(即以字为单位),不足的以 0 填充,图像文件中一个扫描行所占的字节数计算方法: //DataSizePerLine= (biWidth* biBitCount+31)/8;// 一个扫描行所占的字节数 //即对于原始文件,其每行的后面是有补零的,所以读取时应跳过这部分//PS:为什么每行读取字节公式是这样计算的呢?这是因为Windows 规定图像文件中一个扫描行所占的字节数必须是 4 的倍数(即以字为单位),即每个扫描行/////读取的位数必须为32的倍数,向上取整,不足补零,所以要加上32-1,则DataSizePerLine= (biWidth* biBitCount+31)/32*4;//则要计算每个扫描行的补零的字节数//一种写法:int getDiff(Info & info){int DataSizePerline = (info.biWidth * info.biBitCount+31) / 8;// 一个扫描行实际所占的字节数DataSizePerline -= DataSizePerline % 4;//为什么要这行捏,DataSizePerline不是4的倍数吗return DataSizePerline - info.biWidth * info.biBitCount /8;//}//另一种写法int getDiff(Info & info){return 4 - ((info.biWidth * info.biBitCount)/8)%4;//但是这种写法好像不能解决图片2}//接下来便是旋转函数template < class T >bool Trans(ifstream & infile,ofstream & outfile,Header & header,Info & info){Header new_header = header;Info new_info = info;new_info.biWidth = info.biHeight;new_info.biHeight = info.biWidth;int diff = getDiff(info);T* pic = new T[info.biHeight * info.biWidth];for(int i=0;i<info.biHeight;i++)//将src.bmp里的位图数据读入到pic数组中{infile.read((char*)(pic+info.biWidth*i),sizeof(T)*info.biWidth);//读取每行biWidth个像素所占的字节数,即去补零的真实数据infile.seekg(diff,ios::cur);//diff为正,跳过每行补零的字节,向后移动diff个字节}diff = getDiff(new_info);char* null = new char[diff+1];//memset(null,0,diff+1);new_info.biSizeImage = (new_info.biWidth*sizeof(T) + diff) * new_info.biHeight*sizeof(T);//新的位图大小new_header.bfsize = new_info.biSizeImage + sizeof(new_info) + sizeof(new_header);//新的位图文件大小T* new_pic = new T[new_info.biHeight * new_info.biWidth];for(int i=0;i<new_info.biHeight;i++)//将src.bmp里读取到pic数组的位图数据旋转得到dest.bmp的里的位图数据,存入到new_pic数组中{for(int j=0;j<new_info.biWidth;j++){*(new_pic+i*new_info.biWidth+j)= *(pic + j*info.biWidth + new_info.biHeight-1-i);//?????}}outfile.write((char*)&new_header,sizeof(Header));//将文件头写入到dest.bmpoutfile.write((char*)&new_info,sizeof(Info));//将信息头写入到dest.bmpfor(int i=0;i<new_info.biHeight;i++)//将位图数据写入到dest.bmp{outfile.write((char*)(new_pic + new_info.biWidth*i),new_info.biWidth*sizeof(T));//将new_pic里面的数据写到dest.bmp文件outfile.write((char*)null,diff);//每行补零,写到dest.bmp文件}return true;}//总的代码/* * rotatebmp.cpp * *  Created on: 2014-4-17 */#include<iostream>#include<fstream>#include<cstring>#include<string>#pragma pack(1)using namespace std;typedef unsigned char BYTE;typedef unsigned int DWORD;typedef unsigned short WORD;typedef long LONG;class Header//文件头{public:WORD bftype;//位图文件的类型,必须为“BM”DWORD bfsize;//位图文件大小,以字节为单位,整个文件,包括位图与文件头和信息头WORD bfReserved1;//位图文件保留字,必须为0WORD bfReserved2;//位图文件保留字,必须为0DWORD bfOffBits;//位图数据的起始位置,以相对于位图文件头的偏移量表示,以字节为单位};class Info//信息头{public:DWORD biSize;//本类所用的字节数LONG biWidth;//位图的宽度,以像素为单位LONG biHeight;//位图的高度,以像素为单位WORD biPlanes;//目标设备的平面数//不清,必须为1//什么WORD biBitCount;//每个像素所需的位数,必须是1(双色),4(16色),8(256色)或24(真彩色)之一DWORD biCompression;//位图压缩类型,必须是 0(不压缩),1(BI_RLE8压缩类型)或 2(BI_RLE4压缩类型)之一DWORD biSizeImage;//位图的大小,以字节为单位LONG biXPelsPerMeter;//位图水平分辨率,每米像素数LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数DWORD biClrUsed;//位图实际使用的颜色表中的颜色数DWORD biClrImportant;//位图显示过程中重要的颜色数};class RGB24{public:RGB24(){GREEN = 0;RED = 0;BLUE = 0;}BYTE RED;//红色的亮度(值范围在0~255)BYTE GREEN;//绿色的亮度(值范围在0~255)BYTE BLUE;//蓝色的亮度(值范围在0~255)};/*找到每行需要补0的字节数 */int getDiff(Info & info){int DataSizePerline = (info.biWidth * info.biBitCount+31) / 8;// 一个扫描行实际所占的字节数DataSizePerline -= DataSizePerline % 4;return DataSizePerline - info.biWidth * info.biBitCount / 8;//返回}template < class T >bool Trans(ifstream & infile,ofstream & outfile,Header & header,Info & info){Header new_header = header;Info new_info = info;new_info.biWidth = info.biHeight;new_info.biHeight = info.biWidth;int diff = getDiff(info);T* pic = new T[info.biHeight * info.biWidth];for(int i=0;i<info.biHeight;i++)//将src.bmp里的位图数据读入到pic数组中{infile.read((char*)(pic+info.biWidth*i),sizeof(T)*info.biWidth);//读取每行biWidth个像素所占的字节数,即去补零的真实数据infile.seekg(diff,ios::cur);//diff为正,跳过每行补零的字节,向后移动diff个字节}diff = getDiff(new_info);char* null = new char[diff+1];//memset(null,0,diff+1);new_info.biSizeImage = (new_info.biWidth*sizeof(T) + diff) * new_info.biHeight*sizeof(T);//新的位图大小new_header.bfsize = new_info.biSizeImage + sizeof(new_info) + sizeof(new_header);//新的位图文件大小T* new_pic = new T[new_info.biHeight * new_info.biWidth];for(int i=0;i<new_info.biHeight;i++)//将src.bmp里读取到pic数组的位图数据旋转得到dest.bmp的里的位图数据,存入到new_pic数组中{for(int j=0;j<new_info.biWidth;j++){*(new_pic+i*new_info.biWidth+j)= *(pic + j*info.biWidth + new_info.biHeight-1-i);//?????}}outfile.write((char*)&new_header,sizeof(Header));//将文件头写入到dest.bmpoutfile.write((char*)&new_info,sizeof(Info));//将信息头写入到dest.bmpfor(int i=0;i<new_info.biHeight;i++)//将位图数据写入到dest.bmp{outfile.write((char*)(new_pic + new_info.biWidth*i),new_info.biWidth*sizeof(T));//将new_pic里面的数据写到dest.bmp文件outfile.write((char*)null,diff);//每行补零,写到dest.bmp文件}return true;}int main(int argc,char* argv[]){char* src_name;char* dest_name;if(argc == 1){cout<<"use \"src.bmp\" as default input file name,use \"dest.bmp\" as default output file name\n";src_name = new char[10];dest_name = new char[10];strcpy(src_name,"src.bmp");strcpy(dest_name,"dest.bmp");}else{src_name = argv[1];dest_name = argv[2];}Header fileHeader;Info infoHeader;ifstream infile(src_name,ios::in|ios::binary);if(!infile){cout<<"读取文件失败"<<endl;return 0;}ofstream outfile(dest_name,ios::out|ios::binary);infile.read((char*) &fileHeader,sizeof(Header));infile.read((char*) &infoHeader,sizeof(Info));if(infoHeader.biBitCount == 24)Trans<RGB24>(infile,outfile,fileHeader,infoHeader);return 0;}


                                             
0 0
原创粉丝点击