VC中保存BMP位图文件的方法及BMP文件格式带源码实现
MFC中显示.bmp格式的位图

MFC中显⽰.bmp格式的位图最近在看VisualC++ 图像处理的书籍,表⽰⼀直在从基础做起,今天就记录⼀个简单功能的实现,显⽰.bmp格式的位图。
⾸先需要理解的是窗⼝创建的过程包括两个步骤:⾸先擦除窗⼝的背景,然后在对窗⼝进⾏重新绘制。
⼀般⽽⾔,对于单⽂档或多⽂档的MFC程序,显⽰图像的代码要放在OnDraw函数之中。
刚刚说过,窗⼝重绘时,要先将窗⼝的背景擦除,也就是发送WM_ERASEBKGND消息,然后⽤OnEraseBkgnd()函数处理这个消息,所以我们的显⽰图像的代码也可以放在这个函数之中。
当然,这⾥只是为了实现显⽰位图这⼀个功能,在实际⼯程中,要根据实际情况,选择代码放置的地⽅。
下⾯先给出代码,然后⼀⾏⼀⾏地详细解释:BOOL CLoadBitmapView::OnEraseBkgnd(CDC* pDC){// TODO: 在此添加消息处理程序代码和/或调⽤默认值//return FALSE;HBITMAP hBit;hBit=(HBITMAP) LoadImage(NULL,_T("D:\\Axing.bmp"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION); //载⼊图像CBitmap cBit;cBit.Attach(hBit);CDC MemDC;MemDC.CreateCompatibleDC(pDC); //创建与当前设备描述表相适应的内存DCBITMAP bitmap;cBit.GetBitmap(&bitmap);CBitmap *oldBit;oldBit=MemDC.SelectObject(&cBit);CRect rect;GetClientRect(&rect);pDC->BitBlt(100,100,rect.Width()/2.5,rect.Height(),&MemDC,0,0,SRCCOPY);return TRUE;//return CView::OnEraseBkgnd(pDC);}⾸先来解释⼀下HBITMAP、CBitmap、BITMAP三者之间的关系。
用c语言读取并显示bmp图像1

如何在WIN-TC中或TC++3.0中把一张BMP格式的图片显示出来?下面的是<<C & C++编程实例>>随书光盘上的代码,我在TC2.0下编译通过.它是利用了抖动技术显示了8bit和24bit的位图(也就是256色和16M色位图),应该能满足你的需要.不过,我想问下,你老师教过抖动显示吗?#include <stdio.h>#include <dos.h>#include <stdio.h>#include <conio.h>#define NoError 0#define ErrorFileOpen 1#define ErrorFileType 2#define ErrorImageColor 3typedef struct tagBITMAPFILEHEADER{unsigned int bfType;unsigned long bfSize;unsigned int bfReserved1;unsigned int bfReserved2;unsigned long bfoffBits;}BITMAPFILEHEADER;typedef struct tagBITMAPINFOHEADER{unsigned long biSize;unsigned long biWidth;unsigned long biHeight;unsigned int biPlanes;unsigned int biBitCount;unsigned long biCompression;unsigned long biSizeImage;unsigned long biXPelsPerMeter;unsigned long biYPelsPerMeter;unsigned long biClrUsed;unsigned long biClrImportant;} BITMAPINFOHEADER;typedef struct tagRGBQUAD{unsigned char rgbBlue;unsigned char rgbGreen;unsigned char rgbRed;unsigned char rgbReserved;} RGBQUAD;unsigned char PalReg[17]= { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0}; unsigned char StandardPal[48]= {0, 0, 0, 32, 0, 0, 0,32, 0, 32,32, 0, 0, 0,32, 32, 0,32, 0,32,32, 32,32, 32, 48, 48,48, 63, 0, 0, 0,63, 0, 63,63, 0, 0, 0,63, 63, 0,63, 0,63,63, 63,63,63, };unsigned char LightnessMatrix [16][16]= {{ 0,235,59,219,15,231,55,215,2,232,56,217,12,229,52,213},{128,64,187,123,143,79,183,119,130,66,184,120,140,76,180,116},{33,192,16,251,47,207,31,247,34,194,18,248,44,204,28,244},{161,97,144,80,175,111,159,95,162,98,146,82,172,108,156,92},{8,225,48,208,5,239,63,223,10,226,50,210,6,236,60,220},{136,72,176,112,133,69,191,127,138,74,178,114,134,70,188,124},{41,200,24,240,36,197,20,255,42,202,26,242,38,198,22,252},{169,105,152,88,164,100,148,84,170,106,154,90,166,102,150,86},{3,233,57,216,13,228,53,212,1,234,58,218,14,230,54,214},{131,67,185,121,141,77,181,117,129,65,186,122,142,78,182,118},{35,195,19,249,45,205,29,245,32,193,17,250,46,206,30,246},{163,99,147,83,173,109,157,93,160,96,145,81,174,110,158,94},{11,227,51,211,7,237,61,221,9,224,49,209,4,238,62,222},{139,75,179,115,135,71,189,125,137,73,177,113,132,68,190,126},{43,203,27,243,39,199,23,253,40,201,25,241,37,196,21,254},{171,107,155,91,167,103,151,87,168,104,153,89,165,101,149,85},};unsigned char ColorTable[2][2][2]= {{{0,12},{10,14}},{{9,13},{11,15}}}; unsigned char ColorMap[256][3];int ShowBmp(char *FileName);int GetColor(unsigned char R,unsigned char G, unsigned char B,int X,int Y); void SetVideoMode(unsigned char Mode);void SetPalReg(unsigned char *palReg);void SetDacReg(unsigned char *DacReg, int Color, int Count);void PutPixel(int X, int Y, unsigned char Color);/* 主函数*/void main (int argc, char *argv[]){if(argc!=2){printf("Usage:\tSHOW Filename.BMP\n");exit(1);}ShowBmp(argv[1]);}/* 根据图像文件名,读取图像内容并利用抖动技术进行显示*/ int ShowBmp(char *FileName){FILE *Fp;BITMAPFILEHEADER FileHead;BITMAPINFOHEADER InfoHead;RGBQUAD RGB;int N, W,Y,X,C,Color;unsigned char Buffer[4096];Fp=fopen(FileName,"rb");if (Fp==NULL)return(ErrorFileOpen);fread(&FileHead,sizeof(BITMAPFILEHEADER),1,Fp);if(FileHead.bfType!='BM'){fclose(Fp);return(ErrorFileType);}fread(&InfoHead,sizeof(BITMAPINFOHEADER),1,Fp);if(InfoHead.biBitCount!=8 && InfoHead.biBitCount!=24){fclose(Fp);return(ErrorImageColor);}/* 设置显示模式和显示区域*/SetVideoMode(0x12);SetPalReg(PalReg);SetDacReg(StandardPal,0,16);/* 对两种不同色彩数的图像分别进行处理*/if(InfoHead.biBitCount==8) /* 256色*/{for (N=0;N<256;N++){fread(&RGB, sizeof(RGBQUAD),1,Fp);ColorMap[N][0]=RGB.rgbRed;ColorMap[N][1]=RGB.rgbGreen;ColorMap[N][2]=RGB.rgbBlue;}W=(InfoHead.biWidth+3)/4*4;for(Y=InfoHead.biHeight-1;Y>=480;Y--)fread(Buffer,sizeof(unsigned char),W,Fp);for(;Y>0;Y--){fread(Buffer,sizeof(unsigned char),W,Fp);for (X=0;X<InfoHead.biWidth && X<640;X++){C=Buffer[X];Color=GetColor(ColorMap[C][0],ColorMap[C][1],ColorMap[C][2],X,Y); PutPixel (X,Y,Color);}}}else /* 24bits真彩色*/{W=(InfoHead.biWidth*3+3)/4*4;for(Y=InfoHead.biHeight-1;Y>639;Y--)fread(Buffer,sizeof(unsigned char),W,Fp);for(;Y>=0;Y--){fread(Buffer,sizeof(unsigned char),W,Fp);for(X=0;X<InfoHead.biWidth && X<640;X++){C=X*3;Color=GetColor(Buffer[C+2],Buffer[C+1],Buffer[C],X,Y);PutPixel(X,Y,Color);}}}getch();fclose(Fp);SetVideoMode(0x03);return(NoError);}int GetColor(unsigned char R, unsigned char G, unsigned char B, int X, int Y) {unsigned int L=LightnessMatrix[Y & 0x0F][X & 0x0F];return(ColorTable[(unsigned int)R*256/255>L][(unsigned int)G*256/255>L][(unsigned int)B*256/255>L]); }void SetVideoMode(unsigned char Mode){_AH=0x00;_AL=Mode;geninterrupt(0x10);}void SetPalReg(unsigned char *PalReg){_ES=FP_SEG((unsigned char far*)PalReg);_DX=FP_OFF((unsigned char far*)PalReg);_AX=0x1002;geninterrupt(0x10);}void SetDacReg(unsigned char *DacReg,int Color,int Count){_ES=FP_SEG((unsigned char far*)DacReg);_DX=FP_OFF((unsigned char far*)DacReg);_AX=0x1012;_BX=Color;_CX=Count;geninterrupt(0x10);}/* 在对应位置显示像素色彩*/void PutPixel(int X, int Y, unsigned char Color){_AH=0x0C;_AL=Color;_CX=X;_DX=Y;geninterrupt(0x10);}16色位图的显示文:吴进/Luckylai对于象大家常用TC的16色图形模式编程的初学者,如果能在程序里使用图片那就会方便很多了,以前在TC256上看见吴进写的《TC的16色BMP闪电显示(66k) 》的代码,发现写的的确不错,而且绝对能在TC的initgraph()初始化的BGI模式下使用。
Bmp图像存储格式

摘要:本文简单介绍了位图文件的两种存储格式,并且在VC++6.0下实现了读取位图文件中的数据,用SetPixel()函数在窗口中重现图像,最后在程序中实现了一种存储格式到另一种存储格式的转换。
关键字:BMP、灰度位图、24位真彩色位图、存储格式一、前言BMP(Bitmap的缩写)图像是指文件名后缀为BMP的位图图像。
位图图像在计算机中使用很广泛,例如在windows中,记事本、写字板中的文字就是用位图图像表示出来的。
许多以其它格式存储的图像,就是在位图图像的基础上,进行优化处理后得到的,例如JPEG图像等。
在数字图像处理中,许多算法就是针对24位真彩色位图或灰度位图设计的。
因此,很有必要介绍一下位图文件的这两种存储格式。
二、24位真彩色图像存储格式把下图的24位真彩色图像格式在16位编辑器(例如VC编辑器)中打开,可以看到图像的二进制数据。
24位真彩色的二进制数据为:这是24位真彩色位图文件数据一部分。
这一部分数据包括位图文件头、位图信息头和位图阵列三部分。
(一)位图文件头位图文件头用来记录标志文件大小的一些信息,在文件中占14个字节,存储的内容如下:字节 1 2 3 4 5 6 7 8 9 10 11 12 13 14 000000 42 4D CC B4 02 00 00 00 00 00 36 00 00 00 其中:42 4D 为位图的标志,即ASCII码为BMCC B4 02 表示位图文件的总字节数,换算成十进制为(02B4CC)H=(177356)10,即这副图像的大小为177356字节。
00 00 00 00 00 为保留字节,用来存储文件大小的数据。
36 00 00 00 00 表示位图阵列的起始位置,(36)H=(54)10即54字节开始为位图阵列。
(二) 位图信息头位图信息头记录和位图相关的一些信息,在文件中占40个字节,存储的内容如下:字节 1 2 3 4 5 6 7 8 9 10 11121314151600000 0 2800001 6 02C1C511800003 2 012B12B00004 8 0其中:28 00 00 00 表示信息头的长度,(28)H=(40)10,即位图信息头占40个字节。
位图文件(BMP)格式分析以及程序实现

inf.read((char*)&header, sizeof(header));if(header.bfType != 0x4D42)return false;这个很简单,没有什么好说的。
2、加载位图信息头//Load the image information headerBITMAPINFOHEADER infoheader;memset(&infoheader, 0, sizeof(infoheader));inf.read((char*)&infoheader, sizeof(infoheader));m_iImageWidth = infoheader.biWidth;m_iImageHeight = infoheader.biHeight;m_iBitsPerPixel = infoheader.biBitCount;这里我们得到了3各重要的图形属性:宽,高,以及每个像素颜色所占用的位数。
3、行对齐由于Windows在进行行扫描的时候最小的单位为4个字节,所以当图片宽X 每个像素的字节数!= 4的整数倍时要在每行的后面补上缺少的字节,以0填充(一般来说当图像宽度为2的幂时不需要对齐)。
位图文件里的数据在写入的时候已经进行了行对齐,也就是说加载的时候不需要再做行对齐。
但是这样一来图片数据的长度就不是:宽X 高X 每个像素的字节数了,我们需要通过下面的方法计算正确的数据长度://Calculate the image data sizeint iLineByteCnt = (((m_iImageWidth*m_iBitsPerPixel) + 31) >> 5) << 2;m_iImageDataSize = iLineByteCnt * m_iImageHeight;4、加载图片数据对于24位和32位的位图文件,位图数据的偏移量为sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER),也就是说现在我们可以直接读取图像数据了。
VC中保存BMP位图文件的方法及BMP文件格式带源码实现

#include "stdio.h"#include "Windows.h"//几个全局变量,存放读入图像的位图数据、宽、高、颜色表及每像素所占位数(比特) //此处定义全局变量主要为了后面的图像数据访问及图像存储作准备unsigned char *pBmpBuf;//读入图像数据的指针int bmpWidth;//图像的宽int bmpHeight;//图像的高RGBQUAD *pColorT able;//颜色表指针int biBitCount;//图像类型bool readBmp(char *bmpName){//二进制读方式打开指定的图像文件FILE *fp=fopen(bmpName,"rb");if(fp==0) return 0;//跳过位图文件头结构BITMAPFILEHEADERfseek(fp, sizeof(BITMAPFILEHEADER),0);//定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中BITMAPINFOHEADER head;fread(&head, sizeof(BITMAPINFOHEADER), 1,fp);//获取图像宽、高、每像素所占位数等信息bmpWidth = head.biWidth;bmpHeight = head.biHeight;biBitCount = head.biBitCount;//定义变量,计算图像每行像素所占的字节数(必须是4的倍数)int lineByte=(bmpWidth * biBitCount/8+3)/4*4;//灰度图像有颜色表,且颜色表表项为256if(biBitCount==8){//申请颜色表所需要的空间,读颜色表进内存pColorTable=new RGBQUAD[256];fread(pColorTable,sizeof(RGBQUAD),256,fp);}//申请位图数据所需要的空间,读位图数据进内存pBmpBuf=new unsigned char[lineByte * bmpHeight];fread(pBmpBuf,1,lineByte * bmpHeight,fp);//关闭文件fclose(fp);return 1;}bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable){//如果位图数据指针为0,则没有数据传入,函数返回if(!imgBuf)return 0;//颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0int colorTablesize=0;if(biBitCount==8)colorTablesize=1024;//待存储图像数据每行字节数为4的倍数int lineByte=(width * biBitCount/8+3)/4*4;//以二进制写的方式打开文件FILE *fp=fopen(bmpName,"wb");if(fp==0) return 0;//申请位图文件头结构变量,填写文件头信息BITMAPFILEHEADER fileHead;fileHead.bfType = 0x4D42;//bmp类型//bfSize是图像文件4个组成部分之和fileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorT ablesize + lineByte*height;fileHead.bfReserved1 = 0;fileHead.bfReserved2 = 0;//bfOffBits是图像文件前三个部分所需空间之和fileHead.bfOffBits=54+colorTablesize;//写文件头进文件fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);//申请位图信息头结构变量,填写信息头信息BITMAPINFOHEADER head;head.biBitCount=biBitCount;head.biClrImportant=0;head.biClrUsed=0;head.biCompression=0;head.biHeight=height;head.biPlanes=1;head.biSize=40;head.biSizeImage=lineByte*height;head.biWidth=width;head.biXPelsPerMeter=0;head.biYPelsPerMeter=0;//写位图信息头进内存fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);//如果灰度图像,有颜色表,写入文件if(biBitCount==8)fwrite(pColorTable, sizeof(RGBQUAD),256, fp);//写位图数据进文件fwrite(imgBuf, height*lineByte, 1, fp);//关闭文件fclose(fp);return 1;}//调色板与灰度图像的关系void main(){//读入指定BMP文件进内存char readPath[]="tarret.BMP";readBmp(readPath);//输出图像的信息printf("width=%d,height=%d,biBitCount=%d\n",bmpWidth,bmpHeight,biBit Count);//改变灰度图像的颜色表蓝色分量的值,察看前后变化if(biBitCount==8){for(int i=0; i<256;i++){pColorTable[i].rgbBlue = 255-pColorTable[i].rgbBlue;}}//将图像数据存盘char writePath[]="tarret1.BMP";saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorT able);//清除缓冲区,pBmpBuf和pColorT able是全局变量,在文件读入时申请的空间delete []pBmpBuf;if(biBitCount==8)delete []pColorTable;}。
CBmp类

#include "stdafx.h"#include <math.h>class CBmp : public CObject{public:CBmp();CBmp(const CBmp& a);virtual ~CBmp();public:LPBITMAPINFO bmi;LPBYTE pBits;public:BOOL Read(CString FileName); //读入图像BOOL Write(CString FileName); //存储图像int GetPaletteSize() const; //调色板大小int GetBytesPerLine() const; //图像每行实际占字节数int GetWidth() const; //宽度int GetHeight() const; //高度BOOL IsValid() const; //图像是否有效BOOL IsGrayScaleImage() const; //判断是灰度图像BOOL ToGrayScaleImage(); //转换为256级灰度图像BOOL ProduceHistogramData(int PixelNum[]) const; //产生原图直方图void Equalize(); //直方图均衡化处理图像void NegtivePhaseChange(); //反色变换void Binarize(int threshold); //二值化void SegmentalLinearTransformate(int x1,int y1,int x2,int y2);//分段线性变换void LogAlter(int c); //灰度对数变换void PowerAlter(float c, float r, float b); //灰度幂次变换void ExpAlter(float b, float c, float a); //灰度指数变换public:CBmp& operator=(const CBmp& bmp); //重载运算符private:BOOL TwoToGray(); //黑白图像转为256级灰度图像BOOL FourToGray(); //16色彩色图像转为256级灰度图像BOOL EightToGray(); //256色彩色图像转为256级灰度图像BOOL TrueColorToGray(); //真彩色图像转为256级灰度图像CBmp::CBmp(){bmi = NULL;pBits = NULL;}CBmp::CBmp(const CBmp& a){int infoSize = sizeof(BITMAPINFOHEADER) + a.GetPaletteSize() * sizeof(RGBQUAD);bmi = (LPBITMAPINFO)new BYTE[infoSize];memcpy( (LPVOID)bmi, (LPVOID)a.bmi,infoSize);pBits = new BYTE[bmi->bmiHeader.biSizeImage];memcpy( (LPVOID)pBits,(LPVOID)a.pBits,bmi->bmiHeader.biSizeImage);}CBmp::~CBmp(){if(bmi){delete bmi;bmi = NULL;}if(pBits){delete pBits;pBits = NULL;}}CBmp& CBmp::operator=(const CBmp& a){if(this == &a) return *this;if(bmi)delete bmi;if(pBits)delete pBits;int infoSize = sizeof(BITMAPINFOHEADER) + a.GetPaletteSize() * sizeof(RGBQUAD);bmi = (LPBITMAPINFO)new BYTE[infoSize];memcpy( (LPVOID)bmi, (LPVOID)a.bmi,infoSize);pBits = new BYTE[bmi->bmiHeader.biSizeImage];memcpy( (LPVOID)pBits,(LPVOID)a.pBits,bmi->bmiHeader.biSizeImage);return *this;}BOOL CBmp::Read(CString FileName){CFile file;BITMAPFILEHEADER bmfh;//打开文件if(!file.Open(FileName,CFile::modeRead)){AfxMessageBox("File cannot open!");return FALSE;}//读文件信息头file.Read( (LPVOID)&bmfh, sizeof(bmfh) );if(bmfh.bfType != 0x4d42){AfxMessageBox("This is not a bmp file!");return FALSE;}if(bmi){delete bmi;bmi = NULL;}if(pBits){delete pBits;pBits = NULL;}//读位图信息头和调色板int infoSize = bmfh.bfOffBits - sizeof(bmfh);bmi = (LPBITMAPINFO)new BYTE[infoSize];file.Read( (LPVOID)bmi, infoSize);if(bmi->bmiHeader.biBitCount!=1 && bmi->bmiHeader.biBitCount!=4 && bmi->bmiHeader.biBitCount!=8 && bmi->bmiHeader.biBitCount!=24){AfxMessageBox("The number of colors is not valid!");return FALSE;}//读图像数据pBits = new BYTE[bmi->bmiHeader.biSizeImage];file.Read( (LPVOID)pBits, bmi->bmiHeader.biSizeImage);return TRUE;}BOOL CBmp::Write(CString FileName){CFile file;BITMAPFILEHEADER bmfh;if(! (bmi && pBits)){AfxMessageBox("Data is not valid!");return FALSE;}//创建文件if(!file.Open(FileName,CFile::modeCreate | CFile::modeWrite)){AfxMessageBox("File creating fails!");return FALSE;}//填写文件信息头bmfh.bfType = 0x4d42;bmfh.bfReserved1 = bmfh.bfReserved2 = 0;int nInfoSize = sizeof(BITMAPINFOHEADER) + GetPaletteSize() * sizeof(RGBQUAD);bmfh.bfOffBits = sizeof(bmfh) + nInfoSize;bmfh.bfSize = bmfh.bfOffBits + bmi->bmiHeader.biSizeImage;//写文件file.Write( (LPVOID)&bmfh, sizeof(bmfh));file.Write( (LPVOID)bmi, nInfoSize);file.Write( (LPVOID)pBits, bmi->bmiHeader.biSizeImage);return TRUE;}int CBmp::GetPaletteSize() const{switch(bmi->bmiHeader.biBitCount){case 1: return 2;case 4: return 16;case 8: return 256;case 24: return 0;default: return -1;}}int CBmp::GetBytesPerLine() const{return bmi->bmiHeader.biSizeImage / bmi->bmiHeader.biHeight; }int CBmp::GetWidth() const{if(bmi)return bmi->bmiHeader.biWidth;elsereturn 0;}int CBmp::GetHeight() const{if(bmi)return bmi->bmiHeader.biHeight;elsereturn 0;}BOOL CBmp::IsValid() const{return bmi && pBits;}BOOL CBmp::IsGrayScaleImage() const{if(bmi->bmiHeader.biBitCount != 8)return FALSE;else{for(int i = 0; i<256; ++i)if( !(bmi->bmiColors[i].rgbBlue == bmi->bmiColors[i].rgbGreen && bmi->bmiColors[i].rgbGreen == bmi->bmiColors[i].rgbRed) )return FALSE;}return TRUE;}BOOL CBmp::ToGrayScaleImage(){switch(GetPaletteSize()){case 2: return TwoToGray();case 16: return FourToGray();case 256: return EightToGray();case 0: return TrueColorToGray();default: return FALSE;}}BOOL CBmp::TwoToGray(){LPBITMAPINFO newbmi = (LPBITMAPINFO)new BYTE[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];//申请新信息头空间memcpy( (LPVOID)newbmi, (LPVOID)bmi, sizeof(BITMAPINFOHEADER));//拷贝位图信息头newbmi->bmiHeader.biBitCount = 8;//修改位图信息头信息int newBytesPerLine = (int)( (bmi->bmiHeader.biWidth * 8 + 31) / 32 ) * 4;//每行实际字节数newbmi->bmiHeader.biSizeImage = newBytesPerLine * newbmi->bmiHeader.biHeight;//修改位图信息头信息//生成新调色板LPRGBQUAD pRGBQUQD = &(newbmi->bmiColors[0]);for (int i = 0; i < 256; ++i){pRGBQUQD[i].rgbRed = pRGBQUQD[i].rgbGreen = pRGBQUQD[i].rgbBlue = i;pRGBQUQD[i].rgbReserved = 0;}//新图像数据LPBYTE newpBits = new BYTE[newbmi->bmiHeader.biSizeImage];int originalBytePosition, newBytePosition;for (i = 0; i < newbmi->bmiHeader.biHeight; ++i){WORD test = 0x0080;for (int j = 0; j < newbmi->bmiHeader.biWidth; ++j){originalBytePosition = i * GetBytesPerLine() + j / 8;//原图中该像素所在的字节号newBytePosition = i * newBytesPerLine + j;//新图中该像素所在的字节号if(pBits[originalBytePosition] & (test>>(j%8)) )//该像素在原图中对应的数据位newpBits[newBytePosition] = 0xff;elsenewpBits[newBytePosition] = 0;}while(newBytePosition%4 != 3)//处理填充字节newpBits[++newBytePosition] = 0;}delete bmi;bmi = newbmi;delete pBits;pBits = newpBits;return TRUE;}BOOL CBmp::FourToGray(){LPBITMAPINFO newbmi = (LPBITMAPINFO)new BYTE[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];//申请新信息头空间memcpy( (LPVOID)newbmi, (LPVOID)bmi, sizeof(BITMAPINFOHEADER));//拷贝位图信息头newbmi->bmiHeader.biBitCount = 8;//修改位图信息头信息int newBytesPerLine = (int)( (bmi->bmiHeader.biWidth * 8 + 31) / 32 ) * 4;//每行实际字节数newbmi->bmiHeader.biSizeImage = newBytesPerLine * newbmi->bmiHeader.biHeight;//修改位图信息头信息//生成新调色板LPRGBQUAD pRGBQUQD = &(newbmi->bmiColors[0]);for (int i = 0; i < 256; ++i){pRGBQUQD[i].rgbRed = pRGBQUQD[i].rgbGreen = pRGBQUQD[i].rgbBlue = i;pRGBQUQD[i].rgbReserved = 0;}LPBYTE newpBits = new BYTE[newbmi->bmiHeader.biSizeImage];int originalBytePosition, newBytePosition,index;pRGBQUQD = &(bmi->bmiColors[0]);for (i = 0; i < newbmi->bmiHeader.biHeight; ++i){for (int j = 0; j < newbmi->bmiHeader.biWidth; ++j){originalBytePosition = i * GetBytesPerLine() + j / 2;//原图中该像素所在的字节号newBytePosition = i * newBytesPerLine + j;//新图中该像素所在的字节号if(j%2 == 0)//提取前半字节{index = pBits[originalBytePosition] / 16;newpBits[newBytePosition] = (BYTE)( (float)pRGBQUQD[index].rgbRed * 0.299+(float)pRGBQUQD[index].rgbGreen * 0.587+(float)pRGBQUQD[index].rgbBlue * 0.114);}else//提取后半字节{index = pBits[originalBytePosition] % 16;newpBits[newBytePosition] = (BYTE)( (float)pRGBQUQD[index].rgbRed * 0.299+(float)pRGBQUQD[index].rgbGreen * 0.587+(float)pRGBQUQD[index].rgbBlue * 0.114);}}while(newBytePosition%4 != 3)//处理填充字节newpBits[++newBytePosition] = 0;}delete bmi;bmi = newbmi;delete pBits;pBits = newpBits;return TRUE;}BOOL CBmp::EightToGray(){LPBITMAPINFO newbmi = (LPBITMAPINFO)new BYTE[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];//申请新信息头空间memcpy( (LPVOID)newbmi, (LPVOID)bmi, sizeof(BITMAPINFOHEADER));//拷贝位图信息头//生成新调色板LPRGBQUAD pRGBQUQD = &(newbmi->bmiColors[0]);for (int i = 0; i < 256; ++i){pRGBQUQD[i].rgbRed = pRGBQUQD[i].rgbGreen = pRGBQUQD[i].rgbBlue = i;pRGBQUQD[i].rgbReserved = 0;}LPBYTE newpBits = new BYTE[newbmi->bmiHeader.biSizeImage];int BytePosition,index;pRGBQUQD = &(bmi->bmiColors[0]);for (i = 0; i < newbmi->bmiHeader.biHeight; ++i){for (int j = 0; j < newbmi->bmiHeader.biWidth; ++j){BytePosition = i * GetBytesPerLine() + j;//该像素所在的字节号index = pBits[BytePosition];//调色板单元号newpBits[BytePosition] = (BYTE)( (float)pRGBQUQD[index].rgbRed * 0.299+(float)pRGBQUQD[index].rgbGreen * 0.587+ (float)pRGBQUQD[index].rgbBlue * 0.114);}while(BytePosition%4 != 3)//处理填充字节newpBits[++BytePosition] = 0;}delete bmi;bmi = newbmi;delete pBits;pBits = newpBits;return TRUE;}BOOL CBmp::TrueColorToGray(){LPBITMAPINFO newbmi = (LPBITMAPINFO)new BYTE[sizeof(BITMAPINFOHEADER)+ 256 * sizeof(RGBQUAD)];//申请新信息头空间memcpy( (LPVOID)newbmi, (LPVOID)bmi, sizeof(BITMAPINFOHEADER));//拷贝位图信息头newbmi->bmiHeader.biBitCount = 8;//修改位图信息头信息int newBytesPerLine = (int)( (bmi->bmiHeader.biWidth * 8 + 31) / 32 ) * 4;//每行实际字节数newbmi->bmiHeader.biSizeImage = newBytesPerLine * newbmi->bmiHeader.biHeight;//修改位图信息头信息//生成新调色板LPRGBQUAD pRGBQUQD = &(newbmi->bmiColors[0]);for (int i = 0; i < 256; ++i){pRGBQUQD[i].rgbRed = pRGBQUQD[i].rgbGreen = pRGBQUQD[i].rgbBlue = i;pRGBQUQD[i].rgbReserved = 0;}LPBYTE newpBits = new BYTE[newbmi->bmiHeader.biSizeImage];int originalBytePosition, newBytePosition;pRGBQUQD = &(bmi->bmiColors[0]);for (i = 0; i < newbmi->bmiHeader.biHeight; ++i){for (int j = 0; j < newbmi->bmiHeader.biWidth; ++j){originalBytePosition = i * GetBytesPerLine() + j * 3;//原图中该像素所在的字节号newBytePosition = i * newBytesPerLine + j;//新图中该像素所在的字节号newpBits[newBytePosition] = (BYTE)( (float)pBits[originalBytePosition] * 0.114 //blue+(float)pBits[originalBytePosition+1] * 0.587 //green+(float)pBits[originalBytePosition+2] * 0.299); //red}while(newBytePosition%4 != 3)//处理填充字节newpBits[++newBytePosition] = 0;}delete bmi;bmi = newbmi;delete pBits;pBits = newpBits;return TRUE;}BOOL CBmp::ProduceHistogramData(int PixelNum[]) const {if(!IsGrayScaleImage()){AfxMessageBox("This is not a gray scale image!");return FALSE;}//像素数数据初始化for (int i = 0; i < 256; ++i){PixelNum[i] = 0;}//统计各灰度值像素数int LineStart; //每一行第一个像素所在字节号for (i = 0; i < bmi->bmiHeader.biHeight; ++i){LineStart = i * GetBytesPerLine();for (int j = 0; j < bmi->bmiHeader.biWidth; ++j){PixelNum[ pBits[LineStart+j] ]++;}}return TRUE;}void CBmp::Equalize(){int map[256];float totalPixelNum; //像素总数int LineStart; //每一行第一个像素所在字节号//原始直方图if(!ProduceHistogramData(map)){return;}//累计for (int i = 1; i<256; ++i){map[i] = map[i] + map[i-1];}totalPixelNum = (float)map[255];//映射表for (i = 0; i < 256; ++i){map[i] = (int)( 255 * (float)map[i] / totalPixelNum + 0.5);}//实现映射for (i = 0; i < bmi->bmiHeader.biHeight; ++i){LineStart = i * GetBytesPerLine();for (int j = 0; j < bmi->bmiHeader.biWidth; ++j){pBits[LineStart+j] = map[ pBits[LineStart+j] ];}}}void CBmp::NegtivePhaseChange(){if(!IsGrayScaleImage()){AfxMessageBox("This is not a gray scale image!");return;}int LineStart;for (int i = 0; i < bmi->bmiHeader.biHeight; ++i){LineStart = i * GetBytesPerLine();for (int j = 0; j < bmi->bmiHeader.biWidth; ++j){pBits[LineStart+j] = 255 - pBits[LineStart+j];}}}void CBmp::Binarize(int threshold){if(!IsGrayScaleImage()){AfxMessageBox("This is not a gray scale image!");return;}int LineStart;for (int i = 0; i < bmi->bmiHeader.biHeight; ++i){LineStart = i * GetBytesPerLine();for (int j = 0; j < bmi->bmiHeader.biWidth; ++j){if(pBits[LineStart + j] < threshold)pBits[LineStart + j] = 0;elsepBits[LineStart + j] = 255;}}}void CBmp::SegmentalLinearTransformate(int x1,int y1,int x2,int y2){if(!IsGrayScaleImage()){AfxMessageBox("This is not a gray scale image!");return;}int map[256]; //映射for (int i = 0; i < x1; ++i) //区间[0,x1) map[i] = i * y1 / x1;for (; i <= x2; ++i) //区间[x1,x2] map[i] = (i - x1) * (y2 - y1) / (x2 - x1) + y1;for (; i<=255; ++i) //区间(x2,255] map[i] = (i - x2) * (255 - y2) / (255 - x2) + y2;//变换int LineStart;for (i = 0; i < bmi->bmiHeader.biHeight; ++i){LineStart = i * GetBytesPerLine();for (int j = 0; j < bmi->bmiHeader.biWidth; ++j){pBits[LineStart + j] = map[ pBits[LineStart + j] ];}}}void CBmp::LogAlter(int c){if(!IsGrayScaleImage()){AfxMessageBox("This is not a gray scale image!");return;}int map[256]; //映射for (int i = 0; i < 256; ++i){map[i] = (int)(c * log( (double)(1 + i) )) ;if(map[i] > 255){map[i] = 255;break;}}while(i < 256)map[i++] = 255;//变换int LineStart;for (i = 0; i < bmi->bmiHeader.biHeight; ++i){LineStart = i * GetBytesPerLine();for (int j = 0; j < bmi->bmiHeader.biWidth; ++j){pBits[LineStart + j] = map[ pBits[LineStart + j] ];}}}void CBmp::PowerAlter(float c, float r, float b){if(!IsGrayScaleImage()){AfxMessageBox("This is not a gray scale image!");return;}int map[256]; //映射for (int i = 0; i < 256; ++i){map[i] = int(c * pow(i/255.0, r) * 255 + b);if(map[i] < 0)map[i] = 0;else if(map[i] > 255){map[i] = 255;break;}}while(i < 256)map[i++] = 255;//变换int LineStart;for (i = 0; i < bmi->bmiHeader.biHeight; ++i){LineStart = i * GetBytesPerLine();for (int j = 0; j < bmi->bmiHeader.biWidth; ++j){pBits[LineStart + j] = map[ pBits[LineStart + j] ];}}}void CBmp::ExpAlter(float b, float c, float a){if(!IsGrayScaleImage()){AfxMessageBox("This is not a gray scale image!");return;}int map[256]; //映射for (int i = 0; i < 256; ++i){map[i] = int(pow(b,c*(i-a))) - 1;if(map[i] < 0)map[i] = 0;else if(map[i] > 255){map[i] = 255;break;}}while(i < 256)map[i++] = 255;//变换int LineStart;for (i = 0; i < bmi->bmiHeader.biHeight; ++i){LineStart = i * GetBytesPerLine();for (int j = 0; j < bmi->bmiHeader.biWidth; ++j){pBits[LineStart + j] = map[ pBits[LineStart + j] ];}}}。
VC++下的BMP格式图像和PNG格式图像的转换

VC++下的BMP格式图像和PNG格式图像的转换肖峰【摘要】初步探讨了在VC++的BMP格式图像和PNG格式图像的转换.首先分析了BMP和PNG两种图像文件的详细格式,然后在VC++环境下建立了这两种图像格式文件的处理类CBmp和CPng,在这两个类中实现了BMP文件的读取、显示和PNG文件的保存等操作.在理解LZ77压缩算法和霍夫曼编码算法的基础上,在VC++的环境下实现这两种算法.这样,我们就可以读取BMP图像文件,然后将图像显示在程序界面上,通过压缩和编码,从而将对应的BMP图像数据转换为PNG图像数据,实现了图像格式的转换.【期刊名称】《赤峰学院学报(自然科学版)》【年(卷),期】2016(032)003【总页数】2页(P17-18)【关键词】VC++;BMP;PNG;LZ77算法;霍夫曼编码【作者】肖峰【作者单位】安徽大学;安徽职业技术学院学生处,安徽合肥 230001【正文语种】中文【中图分类】TP317.4随着网络的发展,图像越来越成为人们之间重要的信息传输和共享方式.在生活和工作中经常用到的图像格式有BMP、PNG、jpe、gif和 tiff等等.其中 BMP 和PNG 格式是采用的无损压缩图像格式,它们之间格式的互相转换就成了数字图像处理中经常遇到的问题.BMP是最常用最基本的图像文件格式,图像软件基本上都能读取和显示BMP图像格式.和其他图像格式相比,BMP格式是一种非常简单的格式,设计目的是为了能在程序设计中轻松的进行图形编程.它具有比较足够的颜色深度支持,可以支持1 位、2 位、4 位和 8 位的彩色索引图像以及16 位、24 位和 32 位的真彩 RGB 图像.BMP 格式的图像通常都很大,因为他只在4位和8位彩色索引图像中支持最简单的行程编码格式.一般来说BMP图像文件由四部分组成:1.1 位图文件头BMP文件的位图文件头是一种简单的供应用程序识别BMP 文件的文件头.它保存了 BMP 文件签名、文件长度字段和数据等相关信息.1.2 位图信息头位图信息头保存了真正的图像信息,它存储了相关的图像格式、图像大小、压缩方式和颜色说明信息等等.1.3 颜色表这部分在图像文件中不是必须的,有些高彩或者真彩图像是不需要颜色表的.对于少于 256 色的图像,位图数据中的像素就是颜色表的索引,用于将索引值转换成RGB 值.很多时候会把位图信息头和颜色表组合在一起组成位图信息结构.这里需要指出的是由于位图信息的位图信息头字段的定义在不同的系统或者平台上可能存在定义版本不一致的情况,应用程序不应该依靠位图信息去定位位图颜色表,而是应该在运行时根据图像信息头计算出颜色表的偏移量.1.4 位图数据位图数据是图像实际像素保存的地方.通常情况下,图像是对齐到32位边界的扫描线的序列.扫描线的默认次序是由下向上.由下向上表示位图数据中的第一个像素实际上是在屏幕上显示时最后一行扫描线的第一个像素.在每行扫描线内部,像素被压缩在一起以节省空间.由于扫描线是双字节对齐的,在扫描线的结尾可能会加上更多的位将其凑成双字的整数倍.对于使用颜色表的位图,像素数据就是颜色表中的颜色索引值,其他的真彩位图中直接使用 RGB 值.利用 VC++ 实现 BMP 文件的读取、显示和保存,先用VC++ 创建一个文档视图应用程序,所有的功能都会在这个程序中实现.首先我们实现一个 BMP 文件操作的类 CBmp,包括Bmp.h 和 Bmp.Cpp 文件. 其次通过 File 菜单下的打开子菜单来打开 BMP 文件,通过类函数 Read()来判断文件是否打开成功.如果返回值为负,则是读取打开文件失败,则提示打开 BMP 文件失败.如果返回值为正,则是正确打开 BMP 文件,程序继续向下执行.最后通过消息函数来调用类 CBmp 的 Draw()函数来把BMP文件的内容显示到界面上.这样,一个 BMP图像文件就被读取显示在程序中了.PNG 是一种无损压缩的、易传输的光栅图像文件格式,设计目的是用来替代 GIF 和 TIFF 文件格式,并增加一些这两种所不具有的文件特性.PNG 图像文件是现在网络、媒体、游戏中最常用的文件格式之一.相比 BMP 格式文件,PNG 格式文件显得更复杂些.它支持灰度图像、索引彩色图像和真彩图像,并且支持额外的α通道.采样的深度范围是从 1 位到 16 位.采用的压缩算法是LZ77 派生的无损数据压缩算法.3.1 文件结构PNG 数据流包含 PNG 文件签名和数据块序列,每个数据块都有自己的类型和功能.3.1.1 PNG 文件签名PNG 文件签名包含一个 8字节的数据,用来识别该文件是不是 PNG 文件.3.1.2 数据块PNG 包含两种类型的数据块,一种叫关键数据块,有 4种.在每个 PNG 文件中都必须必须包含这四种数据块,另一种叫做辅助数据块,有 14 种,PNG 文件中可以包含也可以不包含,可以包含一种也可以同时包含多种.关键数据块有以下类型:文件头(IHDR)、调色板(PLTE)、图像数据(IDAT)和图像结束数据(IEND).辅助数据块包含了很多信息,这些辅助数据块在 PNG文件中根据需要被包含一部分或者全部包含.数据块结构每个数据块由3个或者4个部分组成:Length:4 字节,块中数据的长度,可以为 0Chunk Type Code(类型码):4 字节,取值范围 65~90 和97~122Chunk Data(数据块数据):可变,数据段CRC:4 字节,循环冗余校验码数据块解析下面我们对四种类型的关键数据块进行解析.(1)IHDR:文件头数据块,按照 PNG 文件规范,整个数据流或者文件中只能有一个文件头数据块.而且它是首个出现在数据流中数据块,数据块的构成格式如下:Width、Height:宽和高,都是 4 字节Bit depth:1 字节,图像采样或调色板索引的位数ColorType:1 字节,图像类型Compression method:1 字节,压缩方法,目前定义了一种压缩方法Filter method:1 字节,目前只定义了一种滤波器方法,0Interlace method:1 字节 0 是没有 Interlace,1 是采用Adam7 方法(2)PLTE:调色板数据块,如果文件是真彩图像或者包含α数据通道的真彩图像,调色板数据块不是必须存在的,如果文件是索引彩色图像,调色板数据块是存在的.调色板数据块包含从 1 到 256 个调色板信息,每一个调色板信息由3个字节组成.(3)IDAT:图像数据块,它存储着压缩后真正的图像数据,可以有多个图像数据块,但是在 PNG 数据流中必须以连续顺序的方式存放.(4)IEND:图像结束数据:放在文件的尾部,是文件结束的标志.它的数据域部分必为空.关于辅助数据块的详细解析这里不再一一列举.3.1 基本原理PNG 使用的是 LZ77 算法派生的一个叫 DEFLATE 的无损压缩算法.DEFLATE 实际上是两种算法的组合实现,它先用 LZ77 算法进行预处理,然后用霍夫曼编码,快速的得到非常不错的压缩效果.LZ77 的基本原理如下:它引入滑动窗口的概念,把这个滑动窗口作为一个动态的字典来维护,用一个三元符号组来表示 offset,len 和分割符.offset表示从文件起始位置到当前 Phase 的起始位置的距离,len 记录当前 Phase 有多少个字符,分割符仅用于分割不同的 Phase.Phase 就是 offset到offset+len 之间的子串减掉分隔符.霍夫曼编码的基本原理:首先要把整个文件中每个符合出现的次数统计下来.然后根据这些符号的次数和出现频率,建立霍夫曼树,通过霍夫曼树生成每个符号的编码.在文件中出现频率高的符号,它对应的霍夫曼编码的长度比较短.对于文件中出现频率低的符号,它的霍夫曼编码的长度比较长.此时再读入一遍文件,逐个编码,得到的码流就是压缩后的数据.3.2 实现过程下面用伪代码来示意 LZ77 的算法过程:假设我们用一个三元组 (i,j,X) 来表示上面提到的三元组.关于霍夫曼编码这里不再赘述.在 VC++ 中实现从 BMP 格式到 PNG 格式的转换,是基于前面的 BMP 文件读取显示保存操作和 LZ77 算法与霍夫曼编码实现的基础之上的,并且同时要求分析PNG 文件的详细格式和读写方法,利用前面建立的 VC++ 下的文档视图程序具体实现这个过程.首先建立基本的应用程序和 CBmp、CPng 类,把类CBmp 和 CPng的成员变量和成员函数初始化.其次把 LZ77 压缩算法和霍夫曼编码算法用 VC++ 代码实现,确保下面的数据处理能正确进行.最后,当前面的这些准备工作完成以后,将 BMP 图像文件中的图像数据通过CBmp类读出来,通过编码程序转换为 PNG 图像数据,并将 BMP 的图像信息写入 PNG 文件的对应域的值,通过 CPng 类的方法将之保存为 PNG 格式文件.首先进行的是读取 BMP文件的操作.在分析和理解BMP 文件的格式以后,我们创建了一个 VC++ 的应用程序,并且实现了详细的类 CBmp用于 BMP 的操作.接下来我们解析了 PNG 文件的格式和其相关的压缩算法,创建和实现了类 CPng 和LZ77 派生算法的处理函数.最后在 VC++ 实现BMP 图像格式文件向 PNG 图像格式文件的转换.〔1〕韩姣.基于 VC++的 BMP 格式图像与 GIF 格式图像转换[J].武汉理工大学学报,2007,29(12):23-25.〔2〕(美)Feng Yuan.Windows 图形编程 [M].北京:机械工业出版社,2002. 〔3〕(美)怀特著,杨浩等.GDI+程序设计[M].北京:清华大学出版社,2002.。
用VC++实现bmp位图打开和显示

用VC++实现bmp位图打开和显示课程名称:数字图象处理实验名称:用C++实现bimp图片的打开与显示班级:姓名:一试验目地:(1)、学会了解C++是使用;(2)、学会用C++解决图像处理问题二、实验内容:用C++语言编写bimp图像显示;三、实验步骤:1、首先建立一个工程。
打开VC++6.0,单击文件【files】→新建【new】→工程【projects】在打开的projects 下选择MFC App Wizard [exe]→在project name 下输入自己的工程名例如(Showpicture)→单击【ok】→在打开的对话框中选择基于单文档【single document】→在第四步“MFC App Wizard step 4 of 6”面板中删掉【隐藏工具栏】和【打印和打印预览】两个选项,之后的全部选择默认,单击finish,出现一个“New Project Information”窗口,单击【ok】。
一个简单的工程框架就建好了。
这是基于MFC App Wizard 自动生成的应用程序,如果我们自己还没有编译任何代码,现在就按下F7键编译程序,接着按Ctr+F5键运行程序,可以看到出现一个完整的带有标题栏、菜单栏的可调边框的应用程序。
2、现在我们正式开始在新建工程Showpicture中进行编程实现bmp位图的打开和显示。
点击左边框中的【ResourceView】框找到【Menu】点开,双击Menu下的图标,在右面的显示框中创建两个菜单:打开,显示原图。
分别双击这两个菜单修改属性:打开ID: ID_FILE_OPEN显示原图ID: IDM_YUANTU3、给这两个菜单建立类向导。
在右边的窗口中右击“打开”,选择“建立类向导”,然后在打开的对话框中按下图1操作,“Class name”选择“CShowpictureDoc” →”Object IDs”中选择“ID_FILE_OPEN” →“Message”中选择“COMMAND”,点击“Add Function”键就会在“Member functions”中如下显示:然后点击“Edit Code”,在自动生成的OnFileOpen函数中编写代码:void CShowpictureDoc::OnFileOpen(){// TODO: Add your command handler code hereCFileDialog fileDlg(TRUE);fileDlg.m_ofn.lpstrTitle="图片打开对话框";fileDlg.m_ofn.lpstrFilter="BMP Files(*.bmp)\0*.bmp\0\0";if(IDOK==fileDlg.DoModal ())filename.Format ("%s",fileDlg.GetPathName());CDib.LoadFile(filename);}同理,操作“显示原图”,如下图2显示:注意这次的“Class name”选择“CShowpictureView”。
VC6.0下bmp位图的读取与显示

实验名称实验一、VC6.0下bmp位图的读取与显示一、实验目的掌握windows BMP格式位图文件的基本格式。
会使用VC++读取图像数据并显示。
二、实验原理及内容在VC6.0环境下,生成MFC应用程序框架。
在已生成的应用程序中,加BMP位图读取与显示的代码,从已有文件中读取bmp 格式文件并在视图中显示。
(一)基本知识:BMP位图文件格式BMP位图文件中主要由4部分内容组成:1、文件头BITMAPFILEHEADER为一STRUCTURE:typedef struct tagBITMAPFILEHEADER {WORD bfType;//文件类型,必须为“BM”或0x424dDWORD bfSize;//文件大小WORD bfReserved1;//保留WORD bfReserved2;//保留DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;2、位图信息头BITMAPINFOHEADER,定义如下:typedef struct tagBITMAPINFOHEADER{DWORD biSize;//structure sizeLONG biWidth;//image widthLONG biHeight;//image heightWORD biPlanes;//value is 1WORD biBitCount;//color bitsDWORD biCompression;//compression or notDWORD biSizeImage;//Image size=width*height( 其中width必须为4的倍数。
LONG biXPelsPerMeter;//LONG biYPelsPerMeter;DWORD biClrUsed;//DWORD biClrImportant;} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;3、调色板typedef struct tagRGBQUAD {BYTE rgbBlue;BYTE rgbGreen;BYTE rgbRed;BYTE rgbReserved;} RGBQUAD;用于存放图像的颜色。
在VC++6.0中将JPG格式图片转换成BMP格式

在VC++6.0中将JPG格式图片转换成BMP格式思路:利用GDI+来完成难点:(1)配置GDI开发环境,添加配置代码(2)在当文档程序中添加转换代码注意:本文档由ybdesire参考网上资料撰写完成,代码已经做过测试,可直接复制张贴实现过程:一、配置GDI开发环境(1)下载GDI+ SDK for Visual C++ 6.0/code/legacy/gdi/GDIPlus.zip下载的GDIPlus文件夹中有Includes,Lib文件夹和gdiplus.dll文件。
将Includes和Lib中的文件分别拷到VC6安装目录中的VC98\include和lib文件夹中;新建MFC项目后,才使用gdiplus.dll,到时候将它拷到对应工程的debug 文件夹下。
(2)新建MFC单文档应用程序show:1、在StdAfx.h 中添加如下代码#include <afxdtctl.h>#define ULONG_PTR ULONG#include <gdiplus.h>using namespace Gdiplus;#pragma comment(lib, "gdiplus.lib")2、如(1)中所说,将gdiplus.dll拷贝到本工程的Debug或Release目录下3、在show.h中的class CShowApp : public CWinApp中添加private:GdiplusStartupInput m_gdiplusStartupInput;ULONG_PTR m_pGdiToken;4、在show.cpp中的BOOL CShowApp::InitInstance()中添加GdiplusStartup(&m_pGdiToken,&m_gdiplusStartupInput,NULL);5、为CShow App添加名字为ExitInstance的虚函数的,并在ExitInstance中添加如下退出GDI+的代码GdiplusShutdown(m_pGdiToken);return CWinApp::ExitInstance();(3)测试GDI+是否配置成功void CShowView::OnDraw(CDC* pDC){CShowDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);Graphics graphics(pDC->m_hDC);Pen pen(Color(255, 0, 255));graphics.DrawLine(&pen, 0, 0, 200, 100);}若能成功运行,表明GDI+配置成功二、添加转换代码,实现将打开的JPG格式文件保存成BMP格式文件(1)在CSshowView中添加如下成员变量CString strOpenFileName;(2)在CSshowView中添加如下成员函数1、在CSshowView中添加ToWChar函数WCHAR* CShowView::ToWChar(char *str){//在GDI+中,有关字符的参数类型全部都是WCHAR类型的//该函数是将传统字符串进行转换static WCHAR buffer[1024];wcsset(buffer,0);MultiByteToWideChar(CP_ACP,0,str,strlen(str),buffer,1024);return buffer;}2、在CSshowView中添加GetImageCLSID函数int CShowView::GetImageCLSID(const WCHAR *format, CLSID *pCLSID) {UINT num=0;UINT size=0;ImageCodecInfo* pImageCodecInfo=NULL;GetImageEncodersSize(&num,&size);if(size==0)return FALSE; // 编码信息不可用// 分配内存pImageCodecInfo=(ImageCodecInfo*)(malloc(size));if(pImageCodecInfo==NULL)return FALSE; // 分配失败// 获得系统中可用的编码方式的所有信息GetImageEncoders(num,size,pImageCodecInfo);// 在可用编码信息中查找 format 格式是否被支持for(UINT i=0;i<num;++i){//MimeType: 编码方式的具体描述if (wcscmp(pImageCodecInfo[ i] .MimeType,format)==0){*pCLSID=pImageCodecInfo[i].Clsid;free(pImageCodecInfo);return TRUE;}}free(pImageCodecInfo);return FALSE;}3、在MFC ClassWixard中重载OnFileOpen()void CShowView::OnFileOpen(){static char szFilter[ ]="常见图像格式文件(*.*)|*.*|";CFileDialogdlgChoseImage(1,NULL,NULL,NULL,szFilter);if(dlgChoseImage.DoModal() ==IDOK){strOpenFileName=dlgChoseImage.GetPathName();// 打开文件后立即在窗口中显示 (重绘客户窗口)this->Invalidate() ;}}4、在MFC ClassWixard中重载OnFileSave()void CShowView::OnFileSave(){if( strOpenFileName.IsEmpty() ){AfxMessageBox("当前没有打开图像文件, 不能进行保存!");return;}// 建立图形对象Graphics graphics(GetDC()->m_hDC);// 装入当前已经打开的图像文件Imageimage(ToWChar(strOpenFileName.GetBuffer(strOpenFileName.GetLength() ) ));CString strFileSave;// 将其他格式的图像全部另存为 BMP 文件static char szFilter[ ]= "位图(*.BMP)|*.BMP|";CFileDialogdlgChoseImage(0,"BMP",strOpenFileName,NULL,szFilter);if(dlgChoseImage.DoModal() ==IDOK){strFileSave=dlgChoseImage.GetPathName();CLSID clsid;if(GetImageCLSID(L"image/bmp", &clsid)){image.Save(ToWChar(strFileSave.GetBuffer(strFileSave.GetLength() )), &clsid, NULL);// 将保存后的图像进行显示strOpenFileName=strFileSave;this->Invalidate() ;}}}参考资料[1]/poonjun/archive/2009/01/04/3701724.aspx[2]/DavidHu/articles/1191635.html[3]/bbsgcon.php?board=VisualC&num=785[4]《图像格式转换在数字仪表识别系统中的应用》刘娜, 汪仁煌, 庞然/*-------------------------------------------------------------*/扩展知识阅读[3] 色彩鲜艳漂亮的高品质图像,一个个形象的Windows图标,高速运动、活灵活现的三维动画,这些生动的图形无一不显示着程序设计者的艺术才华。
【数字图像处理】一、BMP文件的读写

一、BMP文件读写1.BMP文件组成BMP文件有文件头、位图信息头、颜色信息和图像数据等四部分组成。
BMP文件头数据包含BMP文件类型、文件大小和位图起始位置等信息。
其结构定义如下:typedef struct tagBITMAPFILEHEADER{WORD bfType;//位图文件的类型,必须为BMPDWORD bfSize;//位图文件的大小,以字节为单位WORD bfReserved1;//位图文件保留字,必须为0WORD bfReserved2;//位图文件保留字,必须为0DWORD bfOffBits;//位图数据的起始位置,以相对于位图文件头的偏移量表示,以//字节单位}BITMAPFILEHEADER;BMP位图信息头数据用于说明位图的尺寸等信息。
其结构定义如下:typedef struct tagBITMAPINFOHEADER{DWORD biSize;//本结构所占用字节数LONG biWidth;//位图的宽度,以像素为单位LONG biHeight;//位图的高度,以像素为单位WORD biplanes;//目标设备的级别,必须为1WORD biBitCount;//每个像素所需要的位数,必须为1(双色),4(16色),8(256//色)或24(真彩色)之一DWORD biCompression;//位图压缩类型,必须为0(不压缩),1(BI_RLE8压缩类//型)或2(BI_RLE4压缩类型)之一DWORD biSizeIMage;//位图的大小,以字节为单位LONG biXPelsPerMeter;//位图水平分辨率,每米像素数LONG biXPelsPerMeter;// 位图垂直分辨率,每米像素数DWORD biClrUsed;//位图实际使用的颜色表中的颜色数DWORD biClrImportant;//位图显示过程中重要的颜色数}BITMAPINFOHEADER颜色表用于说明位图中的颜色,它有若干个表项,每一表项是一个RGBQUAR类型的结构,定义一种颜色。
C语言读取BMP格式图片

典型的位图文件格式通常包含下面几个数据块:
位图头:保存位图文件的总体信息。 位图信息:保存位图图像的详细信息。 调色板:保存所用颜色的定义。 位图数据:保存一个又一个像素的实际图像。
下面的部分将会详细地描述位图文件中保存的数据。 需要注意的是这是标准位图 的文件格式, 其他一些位图图像可能根据生成文件的应用程序不同所使用格式可 能会有细微的区别。 位图头 这部分是识别信息, 典型的应用程序会首先普通读取这部分数据以确保的确是位 图文件并且没有损坏。
BMP 文件大小 度(width)都以像素为单位。 需要注意的是上面公式中的 54 是位图文件的文件头,
, 其中高度(height)和宽
是彩色调色板的大
小。 如果位图文件不包含调色板,如 24 位,32 位位图,则位图的近似字节数 可以用下面的公式计算:
BMP 文件大小 都以像素为单位。
,其中高度(height)和宽度(wimp 文件格式的描述,就不难发现,读取 bmp 大致只需要用到 fseek,fopen,fread 等函数即可以完成,下面我给出相应的 C 代码,读取的图像头文件信息主要是 offset,width,height,数据信息主要是 r[][],g[][],b[][],同时把数据输出到相应的 txt 文件中。
FILE *fpbmp; FILE *fpout;
fpbmp= fopen("1.bmp", "rb"); if (fpbmp == NULL) { printf("Open bmp failed!!!\n"); return 1; }
fpout= fopen("out.bmp", "wb+"); if (fpout == NULL) { printf("Open out.bmp failed!!!\n"); return 1; }
2.MFC-bmp图片读取保存

第二课 bmp图片格式解析<一>.BMP格式定义BMP文件格式是Windows操作系统推荐和支持的图像文件格式,是一种将内存或显示器的图像数据不经过压缩而直接按位存盘的文件格式,故称位图(bitmap),其扩展名为BMP。
BMP图像文件被分为4个部分:a.位图文件头b.位图信息头c.颜色表d.位图数据a.颜色表中RGBQUAD结构数据的个数有biBitCount来确定:当biBitCount=1,4,8时,分别有2,16,256个表项;当biBitCount=24时,没有颜色表项。
位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:typedef struct tagBITMAPINFO {BITMAPINFOHEADER bmiHeader; // 位图信息头RGBQUAD bmiColors[1]; // 颜色表} BITMAPINFO;b.位图数据位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。
位图的一个像素值所占的字节数: 当biBitCount=1时,8个像素占1个字节;当biBitCount=4时,2个像素占1个字节;当biBitCount=8时,1个像素占1个字节;当biBitCount=24时,1个像素占3个字节;Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31)/ 8) * bi.biHeight。
<二>.BMP图片在MFC工程中的定义存在2个未解问题:a. bmp结构时我定义成系统自带的结构,否则会多2个字节在图片最后为CD;b. 在read中malloc只能申请4字节的空间,但fread(,m_nImage,)读入位图大小个。
第一步:添加BMP信息文件头文件—新建—创建ImageStruct.h—包含BMP格式的文件头部分的结构。
VC++6.0位图的打开显示保存

VC++ 6.0 位图打开、显示和保存操作用到的数据:char *m_pDibData;int m_nBitCount;int m_nHeight;int m_nWidth;CString m_fileName;HGLOBAL m_hDIB;void CBitView::OnFileOpen(){// TODO: Add your command handler code here//打开对话框,并获得要打开的位图的路径,保存在m_fileName中static char szFilter[] = "位图文件(*.bmp;*.dib) | *.bmp;*.dib | All Files(*.*) | *.* ||";CFileDialog dlg(true,"*.bmp",NULL, OFN_HIDEREADONL Y | OFN_OVERWRITEPROMPT,szFilter);if (dlg.DoModal()==IDOK){UpdateData(true);m_fileName = dlg.GetPathName();}//新建CFile类对象dibFile,并用只读的模式打开CFile dibFile;if(!dibFile.Open(m_fileName,CFile::modeRead)){AfxMessageBox("Can not open DIB file...");return;}//接下来读取位图文件的文件头//新建一个位图文件头变量BITMAPFILEHEADER bitmapFileHeader;//从位图文件中读取与位图文件头大小的字节到文件头变量中UINT bitmapFileHeaderSize = dibFile.Read((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER));if (bitmapFileHeaderSize != sizeof(BITMAPFILEHEADER)){AfxMessageBox("Failed in reading file");return;}//判断读取的文件是否为位图文件if (bitmapFileHeader.bfType == 0x4d42){//读取整个位图文件长度DWORD dwFileLength = dibFile.GetLength();/***************************************BMP文件的组成结构1 位图文件头(14字节)(BITMAPFILEHEADER)2 位图信息(包含位图信息头和调色板数据)真彩色的位图是没有调色板数据的,而位图信息头为14字节其结构体为BITMAPINFOHEADER,位图信息的结构体为BITMAPINFO3 像素数据*****************************************///获取位图信息头和像素数据的大小(文件总长度- 位图文件头的长度)DWORD dwSize = dwFileLength - sizeof(BITMAPFILEHEADER);//为位图信息头和像素数据分配大小m_hDIB = (HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE,dwSize);//锁定分配的内存,将返回指向此内存的指针BYTE * m_pdib = (BYTE *)::GlobalLock((HGLOBAL)m_hDIB);//将位图信息头和像素数据一起读入到已分配的内存当中DWORD dwReadSize = dibFile.Read((void*)m_pdib,dwSize);//获取位图信息头和位图信息的指针//位图信息头指针用来获取位图的宽度、高度和每个像素所占字节数//位图信息指针用来在StretchDIBits中显示位图时的参数BITMAPINFO *m_pBitmapInfo = (BITMAPINFO *)m_pdib;BITMAPINFOHEADER *m_pBitmapInfoHeader = (BITMAPINFOHEADER *)m_pdib;m_nWidth = m_pBitmapInfoHeader->biWidth;m_nHeight = m_pBitmapInfoHeader->biHeight;m_nBitCount = m_pBitmapInfoHeader->biBitCount;if (m_nBitCount < 24){AfxMessageBox("打开的不是大于24位的真彩色图片,不能处理,只能显示和保存位图!");}//计算像素数据所在的位置(起始位置+位图信息头的大小)m_pDibData = (char *)m_pdib+m_pBitmapInfoHeader->biSize;//显示像素数据的内容CDC *pDC = GetDC(); //得到当前设备的句柄指针::StretchDIBits(pDC->m_hDC,0,0,m_nWidth,m_nHeight,0,0,m_nWidth,m_nHeight,m_pDib Data,m_pBitmapInfo,DIB_RGB_COLORS,SRCCOPY);::GlobalUnlock((HGLOBAL)m_hDIB);}else{AfxMessageBox("非位图文件");return;}}void CBitView::OnSaveBmp(){// TODO: Add your command handler code here//生成图像的信息头(包括位图文件头和位图信息)//位图文件头占14字节,位图信息头占40字节BITMAPFILEHEADER bf;bf.bfOffBits = 54;bf.bfReserved1 = 0;bf.bfReserved2 = 0;//说明文件大小(位图文件头+ 位图信息头+图片像素所占字节数)bf.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+m_nHeight*m_nWidth*4;//说明文件类型为BMbf.bfType =((WORD)'M'<<8 | 'B');BITMAPINFOHEADER bi;//说明每个像素所占字节数,其值为1、4、8、16、24、32bi.biBitCount = m_nBitCount;//说明图像显示有重要影响的颜色索引的数目,如果是0,表示都重要bi.biClrImportant = 0;//说明图像数据压缩的类型bi.biCompression = 0L;//说明图像的宽度,以像素为单位bi.biWidth = m_nWidth;//说明图像的高度,以像素为单位bi.biHeight = m_nHeight;//目标设备说明位面数,其值总是被设为1bi.biPlanes = 1;//说明BITMAPINFOHEADER结构所需要的字节数bi.biSize = sizeof(BITMAPINFOHEADER);//说明图像的大小,以字节为单位,当用BI_RGB格式时,可设置为0bi.biSizeImage = 0;//说明图像的水平分辨率,用像素/米来表示bi.biXPelsPerMeter = 0;//说明图像的垂直分辨率,用像素/米来表示bi.biYPelsPerMeter = 0;//打开保存对话框,获取保存路径及文件名static char szFilter[] = "位图文件(*.bmp;*.dib) | *.bmp;*.dib | All Files(*.*) | *.* ||";CFileDialog dlg(false,"*.bmp",NULL,OFN_HIDEREADONL Y | OFN_OVERWRITEPROMPT,szFilter);if (dlg.DoModal() == IDOK){UpdateData(TRUE);m_fileName = dlg.GetPathName();}else{return;}//建立CFile对像准备保存图片CFile file;if(!file.Open(m_fileName,CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)){AfxMessageBox("cant write BMP file");return;}//写入位图文件头file.Write(&bf,14);//写入位图信息头file.Write(&bi,sizeof(BITMAPINFOHEADER));//获得图像每一行所占的字节数long lWidthBytes = (m_nWidth*m_nBitCount +31)/32*4;//写入整个的像素矩阵中的数据file.Write(m_pDibData,m_nHeight*lWidthBytes);//写入完毕file.Close();}void CBitView::OnShowBMP(){// TODO: Add your command handler code hereCDC *pDC = GetDC();BYTE *lpdib = (BYTE *)::GlobalLock((HGLOBAL)m_hDIB);BITMAPINFO *m_pBitmapInfo = (BITMAPINFO *)lpdib;::StretchDIBits(pDC->m_hDC,0,0,m_nWidth,m_nHeight,0,0,m_nWidth,m_nHeight,m_pDib Data,m_pBitmapInfo,DIB_RGB_COLORS,SRCCOPY);::GlobalUnlock((HGLOBAL)m_hDIB);}。
vc保存Bitmap到文件

vc保存Bitmap到文件CFileDialog dlg(false,"*.bmp",NULL,NULL,"*.bmp|*.bmp||");if (dlg.DoModal()==IDOK){SaveBitmapToFile(hBitmap,dlg.GetPathName());PostQuitMessage(0);}//------------保存Bitmap到文件---------------BOOL SaveBitmapToFile(HBITMAP hBitmap, LPCTSTR lpFileName ){HDC hDC; //设备描述表int iBits; //当前显示分辨率下每个像素所占字节数WORD wBitCount; //位图中每个像素所占字节数DWORD dwPaletteSize=0, //定义调色板大小,位图中像素字节大小,位图文件大小,写入文件字节数dwBmBitsSize,dwDIBSize, dwWritten;BITMAP Bitmap; //位图属性结构BITMAPFILEHEADER bmfHdr; //位图文件头结构BITMAPINFOHEADER bi; //位图信息头结构LPBITMAPINFOHEADER lpbi; //指向位图信息头结构HANDLE fh, hDib, hPal,hOldPal=NULL; //定义文件,分配内存句柄,调色板句柄//计算位图文件每个像素所占字节数HDC hWndDC = CreateDC("DISPLAY",NULL,NULL,NULL);hDC = ::CreateCompatibleDC( hWndDC ) ;iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);DeleteDC(hDC);if (iBits <= 1)wBitCount = 1;else if (iBits <= 4)wBitCount = 4;else if (iBits <= 8)wBitCount = 8;else if (iBits <= 24)wBitCount = 24;elsewBitCount = 24 ;//计算调色板大小if (wBitCount <= 8)dwPaletteSize = (1 << wBitCount) * sizeof(RGBQUAD);//设置位图信息头结构GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);bi.biSize = sizeof(BITMAPINFOHEADER);bi.biWidth = Bitmap.bmWidth;bi.biHeight = Bitmap.bmHeight;bi.biPlanes = 1;bi.biBitCount = wBitCount;bi.biCompression = BI_RGB;bi.biSizeImage = 0;bi.biXPelsPerMeter = 0;bi.biYPelsPerMeter = 0;bi.biClrUsed = 0;bi.biClrImportant = 0;dwBmBitsSize = ((Bitmap.bmWidth * wBitCount+31)/32) * 4 * Bitmap.bmHeight ;//为位图内容分配内存hDib = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAP INFOHEADER));lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);*lpbi = bi;// 处理调色板hPal = GetStockObject(DEFAULT_PALETTE);if (hPal){hDC = ::GetDC(NULL);hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);RealizePalette(hDC);}// 获取该调色板下新的像素值GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight,(LPSTR)lpbi + sizeof(BITMAPINFOHEADER)+dwPaletteSize,(LPBITMAPINFO )lpbi, DIB_RGB_COLORS);//恢复调色板if (hOldPal){SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);RealizePalette(hDC);::ReleaseDC(NULL, hDC);}//创建位图文件fh = CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);if (fh == INVALID_HANDLE_VALUE)return FALSE;// 设置位图文件头bmfHdr.bfType = 0x4D42; // "BM"dwDIBSize = sizeof(BITMAPFILEHEADER)+ sizeof(BITMAPINFOHEADER)+ dwPaletteSize + dwBmBitsSize;bmfHdr.bfSize = dwDIBSize;bmfHdr.bfReserved1 = 0;bmfHdr.bfReserved2 = 0;bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)+ (DWORD)sizeof(BITMAPINFOHEADER)+ dwPaletteSize;// 写入位图文件头WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);// 写入位图文件其余内容WriteFile(fh, (LPSTR)lpbi, dwDIBSize,&dwWritten, NULL);//清除GlobalUnlock(hDib);GlobalFree(hDib);CloseHandle(fh);return TRUE;}。
保存MFC的CBitmap对象中的图象到一个BMP文件中

保存MFC的CBitmap对象中的图象到一个BMP文件中BOOL SaveBmp(HBITMAP hBitmap, CString FileName) //FileName包括路径和文件的全名//hBitmap=(HBITMAP )bm.GetSafeHandle(); CBitmap bm;{//设备描述表HDC hDC;//当前分辨率下每象素所占字节数int iBits;//位图中每象素所占字节数WORD wBitCount;//定义调色板大小,位图中像素字节大小,位图文件大小,写入文件字节数DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;//位图属性结构BITMAP Bitmap; //位图文件头结构BITMAPFILEHEADER bmfHdr; //位图信息头结构BITMAPINFOHEADER bi; //指向位图信息头结构 LPBITMAPINFOHEADER lpbi; //定义文件,分配内存句柄,调色板句柄HANDLE fh, hDib, hPal,hOldPal=NULL;//计算位图文件每个像素所占字节数hDC = CreateDC("DISPLAY", NULL, NULL, NULL);iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);DeleteDC(hDC);if (iBits <= 1) wBitCount = 1;else if (iBits <= 4) wBitCount = 4;else if (iBits <= 8) wBitCount = 8;else wBitCount = 24;GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&Bitmap);bi.biSize = sizeof(BITMAPINFOHEADER);bi.biWidth = Bitmap.bmWidth;bi.biHeight = Bitmap.bmHeight;bi.biPlanes = 1;bi.biBitCount = wBitCount;bi.biCompression = BI_RGB;bi.biSizeImage = 0;bi.biXPelsPerMeter = 0;bi.biYPelsPerMeter = 0;bi.biClrImportant = 0;bi.biClrUsed = 0;dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;//为位图内容分配内存hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER)); lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);*lpbi = bi;// 处理调色板 hPal = GetStockObject(DEFAULT_PALETTE);if (hPal){hDC = ::GetDC(NULL);hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);RealizePalette(hDC);}// 获取该调色板下新的像素值GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)+dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);//恢复调色板 if (hOldPal){::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);RealizePalette(hDC);::ReleaseDC(NULL, hDC);}//创建位图文件 fh = CreateFile(FileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);if (fh == INV ALID_HANDLE_V ALUE) return FALSE;// 设置位图文件头bmfHdr.bfType = 0x4D42; // "BM"dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; bmfHdr.bfSize = dwDIBSize;bmfHdr.bfReserved1 = 0;bmfHdr.bfReserved2 = 0;bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) +(DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;// 写入位图文件头WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);// 写入位图文件其余内容// WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);//清除 GlobalUnlock(hDib);GlobalFree(hDib);CloseHandle(fh);return TRUE;}。
VC打开图片保存为数组,然后数组显示为图片,直接操作像素值

显示.bmp文件:操作xxDoc.h, xxDoc.cpp, xxView.cpp即可完成1、新建单文档文件BmpView2、在BmpViewDoc.h中添加// Attributespublic:BITMAPINFOHEADER bi; //信息头RGBQUAD* quad; //调色板BYTE* lpBuf; //图像数据BITMAPINFO* pbi;int flag; //标志表示是否打开了bmp文件,并在构造函数中初始化为0,Sorinleeint numQuad; //调色板数目BYTE* lpshowbuf; //用于显示的图像数据int zoomfactor; //缩放比率BYTE** image; //原文是把它作为局部变量,在PrepareShowdata()函数中定义Sorinlee3、在BmpViewDoc.cpp的OnFileOpen() 中添加// TODO: Add your command handler code hereflag=1;//设定标志SorinleeLPCTSTR lpszFilter="BMP Files(*.bmp)|*.bmp|任何文件|*.*||";CFileDialogdlg1(TRUE,lpszFilter,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,lpszFilter,NULL); CString filename;CFile file;BITMAPFILEHEADER bf;//打开文件对话框if(dlg1.DoModal()==IDOK){filename=dlg1.GetPathName();if(file.Open(filename,CFile::modeRead|CFile::shareDenyNone,NULL)==0){//读取文件失败AfxMessageBox("无法打开文件!",MB_OK,0);return;}//读取文件头file.Read(&bf,sizeof(bf));//判断是否是BMP文件if(bf.bfType!=0x4d42)//'BM'{AfxMessageBox("非BMP文件!",MB_OK,0);return;}//判断文件是否损坏if(file.GetLength()!=bf.bfSize){AfxMessageBox("文件已损坏,请检查!",MB_OK,0);return;}//读文件信息头file.Read(&bi,sizeof(bi));//计算调色板数目numQuad=0;if(bi.biBitCount<24){numQuad=1<<bi.biBitCount;}//为图像信息pbi申请空间pbi=(BITMAPINFO*)HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+numQuad*sizeof(R GBQUAD));memcpy(pbi,&bi,sizeof(bi));quad=(RGBQUAD*)((BYTE*)pbi+sizeof(BITMAPINFOHEADER));//读取调色板if(numQuad!=0){file.Read(quad,sizeof(RGBQUAD)*numQuad);}//为图像数据申请空间bi.biSizeImage=bf.bfSize-bf.bfOffBits;lpBuf=(BYTE*)HeapAlloc(GetProcessHeap(),0,bi.biSizeImage);//读取图像数据file.Read(lpBuf,bi.biSizeImage);//图像读取完毕,关闭文件,设置标志file.Close();flag=1;zoomfactor=1;lpshowbuf=NULL;PrepareShowdata();UpdateAllViews(NULL,0,NULL);}4、在BmpViewDoc 中添加成员函数bool CBmpViewDoc::PrepareShowdata()//BYTE** image;//原文是在这里把这个定义为局部变量SorinleeBYTE** originimage;int i,j;int linewidth;if(lpshowbuf!=NULL)HeapFree(GetProcessHeap(),0,lpshowbuf);if(zoomfactor>=1){//放大pbi->bmiHeader.biHeight=bi.biHeight*zoomfactor;pbi->bmiHeader.biWidth=bi.biWidth*zoomfactor;//每行四字节补齐,计算每行字节数:linewidth=(pbi->bmiHeader.biWidth*pbi->bmiHeader.biBitCount+31)/32*4;//计算显示图像所需内存大小pbi->bmiHeader.biSizeImage=linewidth*pbi->bmiHeader.biHeight;//申请内存lpshowbuf=(BYTE*)HeapAlloc(GetProcessHeap(),0,pbi->bmiHeader.biSizeImage); //生成对lpshowbuf的二维数组索引:image=new BYTE*[pbi->bmiHeader.biHeight];for(i=0;i<pbi->bmiHeader.biHeight;i++)image[i]=lpshowbuf+i*linewidth;originimage=new BYTE*[bi.biHeight];for(i=0;i<bi.biHeight;i++)originimage[i]=lpBuf+i*bi.biSizeImage/bi.biHeight;//赋值if(bi.biBitCount<24){for(i=0;i<pbi->bmiHeader.biHeight;i++)for(j=0;j<linewidth;j++)image[i][j]=originimage[i/zoomfactor][j/zoomfactor];}else if(bi.biBitCount==24){//24位真彩色for(i=0;i<pbi->bmiHeader.biHeight;i++)for(j=0;j<pbi->bmiHeader.biWidth;j++){image[i][j*3]=originimage[i/zoomfactor][(j/zoomfactor)*3];image[i][j*3+1]=originimage[i/zoomfactor][(j/zoomfactor)*3+1];image[i][j*3+2]=originimage[i/zoomfactor][(j/zoomfactor)*3+2];}}else{//32位色for(i=0;i<pbi->bmiHeader.biHeight;i++)for(j=0;j<pbi->bmiHeader.biWidth;j++){image[i][j*4]=originimage[i/zoomfactor][(j/zoomfactor)*4];image[i][j*4+1]=originimage[i/zoomfactor][(j/zoomfactor)*4+1];image[i][j*4+2]=originimage[i/zoomfactor][(j/zoomfactor)*4+2];image[i][j*4+3]=originimage[i/zoomfactor][(j/zoomfactor)*4+3];}}}else{//缩小pbi->bmiHeader.biHeight=bi.biHeight/(-zoomfactor);pbi->bmiHeader.biWidth=bi.biWidth/(-zoomfactor);//每行四字节补齐,计算每行字节数:linewidth=(pbi->bmiHeader.biWidth*pbi->bmiHeader.biBitCount+31)/32*4;//计算显示图像所需内存大小pbi->bmiHeader.biSizeImage=linewidth*pbi->bmiHeader.biHeight;//申请内存lpshowbuf=(BYTE*)HeapAlloc(GetProcessHeap(),0,pbi->bmiHeader.biSizeImage); //生成对lpshowbuf的二维数组索引:image=new BYTE*[pbi->bmiHeader.biHeight];for(i=0;i<pbi->bmiHeader.biHeight;i++)image[i]=lpshowbuf+i*linewidth;originimage=new BYTE*[bi.biHeight];for(i=0;i<bi.biHeight;i++)originimage[i]=lpBuf+i*bi.biSizeImage/bi.biHeight;//赋值if(bi.biBitCount<24){for(i=0;i<pbi->bmiHeader.biHeight;i++)for(j=0;j<linewidth;j++)image[i][j]=originimage[i*(-zoomfactor)][j*(-zoomfactor)];}else if(bi.biBitCount==24){//24位真彩色for(i=0;i<pbi->bmiHeader.biHeight;i++)for(j=0;j<pbi->bmiHeader.biWidth;j++){image[i][j*3]=originimage[i*(-zoomfactor)][(j*(-zoomfactor))*3];image[i][j*3+1]=originimage[i*(-zoomfactor)][(j*(-zoomfactor))*3+1];image[i][j*3+2]=originimage[i*(-zoomfactor)][(j*(-zoomfactor))*3+2];}}else{//32位色for(i=0;i<pbi->bmiHeader.biHeight;i++)for(j=0;j<pbi->bmiHeader.biWidth;j++){image[i][j*4]=originimage[i*(-zoomfactor)][(j*(-zoomfactor))*4];image[i][j*4+1]=originimage[i*(-zoomfactor)][(j*(-zoomfactor))*4+1];image[i][j*4+2]=originimage[i*(-zoomfactor)][(j*(-zoomfactor))*4+2];image[i][j*4+3]=originimage[i*(-zoomfactor)][(j*(-zoomfactor))*4+3];}}}Invalidate();//使窗口重绘Sorinlee,不明白为什么,不加这句就不显示图像了delete []image;delete []originimage;return TRUE;5、在BmpViewView中添加WM_PAINT消息,在消息响应函数中添加CPaintDC dc(this); // device context for painting// TODO: Add your message handler code here//得到文档指针CBmpViewDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);//是否已打开某个BMP文件,为了直接操作数组的每一个像素,我屏蔽掉了if语句里面的内容Sorinlee if(pDoc->flag==1){//指定是显示的颜色SetDIBitsToDevice(dc.m_hDC,0,0,pDoc->pbi->bmiHeader.biWidth,pDoc->pbi->bmiHeader.biHeight,0,0,0,pDoc->pbi->bmiHeader.biHeight,pDoc->lpshowbuf,pDoc->pbi,DIB_RGB_COLORS);}// Do not call CView::OnPaint() for painting messagesif(flag){//for(int i=0;i<pbi->bmiHeader.biHeight;i++)//图像倒立for(int i= pbi->bmiHeader.biHeight-1;i>0;i--)//图像正显for(int j=0;j<pbi->bmiHeader.biWidth;j++)//dc.SetPixel(i,j,RGB(image[i][j*3],image[i][j*3+1],image[i][j*3+2]));dc.SetPixel(i,j,RGB(image[i][j*3+2],image[i][j*3+1],image[i][j*3]));}把图像显示为点阵形式Sorinlee//创建画笔,画点阵COLORREF c olor;CPoint point(40,40);if(flag){//for(i=0;i<pbi->bmiHeader.biHeight;i++)//图像倒立for(i= pbi->bmiHeader.biHeight-1;i>0;i--)//图像正显{for(j=0;j<pbi->bmiHeader.biWidth;j++){CPen pen(PS_SOLID,5,color);dc.SelectObject(&pen);CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));dc.SelectObject(pBrush);//dc.SetPixel(i,j,RGB(image[i][j*3],image[i][j*3+1],image[i][j*3+2]));color=RGB(image[i][j*3],image[i][j*3+1],image[i][j*3+2]);dc.Ellipse(point.x-2,point.y-2,point.x+2,point.y+2);point.x+=12;}point.y+=12;point.x=40;}} */。
将CBitmap类保存为bmp文件(VC++)

做了一个截屏程序,提供了两种功能:将图象保存为文件,保存到剪切板。
后面一种相对简单代码量少,将图像保存为文件相对复杂,网上也有很多这样的函数(但是基本上都来自一个版本),COPY了一个过来,不能运行,但我相信程序的大部分功能是好的,以前也没有接触过类似的东西,所以一步步把它看懂,然后修改正确,也对代码结构作了调整。
相信能被更好的理解。
要保存为BMP文件,首先肯定要了解BMP文件的格式。
网上查资料知BMP文件的结构可以分为三个部分:1,文件的头结构,记录了整个文件的大小,图象类型,MFC类型为BITMAPFILEHEADER 2。
图象信息的头结构,记当了图象的一些信息,如大小,颜色深度等。
类型为:BITMAPINFOHEADER3. 图象各个象素的颜色值,这部分应该是文件的主体了。
有了以上的信息要保存BMP文件的步骤就很明显了。
创建这两个结构,并初始化,边同象素颜色值写入文件即可,我下面的代码遵循的就是这个步骤,所以感觉条理应该比较清楚。
直接上代码(以下代码在VC 6。
0中通过测试)void MySaveBmpT ofile(HBITMAP hbmp, CString path){//参数说明: hbmp :需保存的图象的句柄path :保存路径//定义文件头结构BITMAPFILEHEADER fileHead;int fileHeadLen = sizeof( BITMAPFILEHEADER );//定义图象信息结构BITMAPINFOHEADER bmpHead;int bmpHeadLen =sizeof( BITMAPINFOHEADER );BITMAP bmpObj;GetObject( hbmp, sizeof(BITMAP), &bmpObj );DWORD fileSizeInByte; //文件总的字节大小//获取系统颜色深度,即每个象素用多少位表还示DWORD PixelSizeInBit;CDC srcDC; //系统屏幕设备描述表srcDC.CreateDC( "DISPLAY", NULL, NULL, NULL);PixelSizeInBit=srcDC.GetDeviceCaps( BITSPIXEL ) * srcDC.GetDeviceCaps( PLANES ); fileSizeInByte = fileHeadLen + bmpHeadLen +bmpObj.bmWidth*bmpObj.bmHeight*PixelSizeInBit/8;//初始化文件头结构fileHead.bfOffBits = fileHeadLen + bmpHeadLen;fileHead.bfReserved1=0;fileHead.bfReserved2=0;fileHead.bfSize = fileSizeInByte;fileHead.bfType = 0x4D42;///初始图像信息结构bmpHead.biBitCount = PixelSizeInBit;bmpHead.biCompression = BI_RGB;bmpHead.biPlanes = 1;bmpHead.biHeight = bmpObj.bmHeight;bmpHead.biWidth = bmpObj.bmWidth;bmpHead.biSize = bmpHeadLen;//为文件分配空间PBYTE pFile=new byte[ fileSizeInByte ];memset( pFile, 0, fileSizeInByte );//填充文件头部memcpy( pFile, (PBYTE)&fileHead, fileHeadLen);//填充文件信息头部结构memcpy( pFile+fileHeadLen, (PBYTE)&bmpHead, bmpHeadLen);//填充象素部分GetDIBits( srcDC.m_hDC, hbmp, 0, bmpObj.bmHeight, pFile+fileHeadLen+bmpHeadLen, (LPBITMAPINFO)(pFile+fileHeadLen), DIB_RGB_COLORS);//打开文件并写入数据HANDLE hFile;hFile=CreateFile( path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);if( hFile==INVALID_HANDLE_VALUE ){MessageBox( "创建文件失败" );return;}DWORD nByteTransfered;WriteFile( hFile, pFile, fileSizeInByte, &nByteTransfered, NULL);CloseHandle( hFile );//清理delete pFile;srcDC.DeleteDC();}保存成功以后,可以用16进制编辑器,打开BMP文件,可以按照在pFile中写入的顺序对里面的文件进行解析,第一个双字节正是写入的0x4D42,哈哈。
C语言BMP图片处理

C语言 BMP图片处理BMP是bitmap的缩写形式,bitmap顾名思义,就是位图也即Windows位图。
它一般由4部分组成:文件头信息块、图像描述信息块、颜色表(在真彩色模式无颜色表)和图像数据区组成。
在系统中以BMP为扩展名保存。
打开Windows的画图程序,在保存图像时,可以看到三个选项:2色位图(黑白)、16色位图、256色位图和24位位图。
这是最普通的生成位图的工具,在这里讲解的BMP位图形式,主要就是指用画图生成的位图(当然,也可以用其它工具软件生成)。
现在讲解BMP的4个组成部分:1.文件头信息块0000-0001:文件标识,为字母ASCII码“BM”。
0002-0005:文件大小。
填写。
0006-0009:保留,每字节以“00”000A-000D:记录图像数据区的起始位置。
各字节的信息依次含义为:文件头信息块大小,图像描述信息块的大小,图像颜色表的大小,保留(为01)。
2.图像描述信息块000E-0011:图像描述信息块的大小,常为28H。
0012-0015:图像宽度。
0016-0019:图像高度。
001A-001B:图像的plane(平面?)总数(恒为1)。
001C-001D:记录像素的位数,很重要的数值,图像的颜色数由该值决定。
001E-0021:数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩)。
0022-0025:图像区数据的大小。
0026-0029:水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H 填写。
002A-002D:垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H 填写。
002E-0031:此图像所用的颜色数,如值为0,表示所有颜色一样重要。
3.颜色表颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。
其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(像素的透明度值,一般不需要)。
24位真彩色位图(bmp)读取代码

BITMAP INFO* pBmpIn fo;BYTE * pBmpDa ta;BITMAP FILEH EADER bmpHea der;BITMAP INFOH EADER bmpInf o;CFilebmpFil e;CStrin g strFil eName;CStrin g strFil ter = "位图文件(*.bmp)|*.b mp|所有文件(*.*)|*.*|";CFileD ialog dlg(TRUE,NULL,NULL,NULL,strFil ter,this);if (!dlg.DoModa l() == IDOK) return;strFil eName = dlg.GetPat hName();/// 通过读取位图文件显示位图if(!bmpFil e.Open(strFil eName,CFile::modeRe ad|CFile::typeBi nary)) return;if (bmpFil e.Read(&bmpHea der,sizeof(BITMAP FILEH EADER)) != sizeof(BITMAP FILEH EADER)) {AfxMes sageB ox("read bmp header failed!");return;}if (bmpHea der.bfType != 0x4d42){AfxMes sageB ox("invali d file type!");return;}if (bmpFil e.Read(&bmpInf o,sizeof(BITMAP INFOH EADER)) != sizeof(BITMAP INFOH EADER)) {AfxMes sageB ox("read bmp inforheader failed!");return;}if (bmpInf o.biBitC ount!= 24){AfxMes sageB ox("File is not 24 bit.Applic ation doesn't suppor t this kind of file!");return;}pBmpIn fo = (BITMAP INFO*)new char[sizeof(BITMAP INFOH EADER)];if (!pBmpIn fo){AfxMes sageB ox("memory error!");return;}memcpy(pBmpIn fo,&bmpInf o,sizeof(BITMAP INFOH EADER));DWORDdataBy tes = bmpHea der.bfSize - bmpHea der.bfOffB its;pBmpDa ta = (BYTE*)new char[dataBy tes];if (!pBmpDa ta){AfxMes sageB ox("memory error!");delete pBmpDa ta;return;}if (bmpFil e.Read(pBmpDa ta,dataBy tes) != dataBy tes){AfxMes sageB ox("Read bmp data failed!");delete pBmpIn fo;delete pBmpDa ta;return;}bmpFil e.Close();CClien tDC *pDC = new CClien tDC(this);pDC->SetStr etchB ltMod e(COLORO NCOLO R);Stretc hDIBi ts(pDC->GetSaf eHdc(),0,0,bmpInf o.biWidt h,bmpInf o.biHeig ht,0,0,bmpInf o.biWidt h,bmpInf o.biHeig ht,pBmpDa ta,p BmpIn fo,DIB_RG B_COL ORS,SRCCOP Y);。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include "stdio.h"#include "Windows.h"//几个全局变量,存放读入图像的位图数据、宽、高、颜色表及每像素所占位数(比特) //此处定义全局变量主要为了后面的图像数据访问及图像存储作准备unsigned char *pBmpBuf;//读入图像数据的指针int bmpWidth;//图像的宽int bmpHeight;//图像的高RGBQUAD *pColorT able;//颜色表指针int biBitCount;//图像类型bool readBmp(char *bmpName){//二进制读方式打开指定的图像文件FILE *fp=fopen(bmpName,"rb");if(fp==0) return 0;//跳过位图文件头结构BITMAPFILEHEADERfseek(fp, sizeof(BITMAPFILEHEADER),0);//定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中BITMAPINFOHEADER head;fread(&head, sizeof(BITMAPINFOHEADER), 1,fp);//获取图像宽、高、每像素所占位数等信息bmpWidth = head.biWidth;bmpHeight = head.biHeight;biBitCount = head.biBitCount;//定义变量,计算图像每行像素所占的字节数(必须是4的倍数)int lineByte=(bmpWidth * biBitCount/8+3)/4*4;//灰度图像有颜色表,且颜色表表项为256if(biBitCount==8){//申请颜色表所需要的空间,读颜色表进内存pColorTable=new RGBQUAD[256];fread(pColorTable,sizeof(RGBQUAD),256,fp);}//申请位图数据所需要的空间,读位图数据进内存pBmpBuf=new unsigned char[lineByte * bmpHeight];fread(pBmpBuf,1,lineByte * bmpHeight,fp);//关闭文件fclose(fp);return 1;}bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable){//如果位图数据指针为0,则没有数据传入,函数返回if(!imgBuf)return 0;//颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0int colorTablesize=0;if(biBitCount==8)colorTablesize=1024;//待存储图像数据每行字节数为4的倍数int lineByte=(width * biBitCount/8+3)/4*4;//以二进制写的方式打开文件FILE *fp=fopen(bmpName,"wb");if(fp==0) return 0;//申请位图文件头结构变量,填写文件头信息BITMAPFILEHEADER fileHead;fileHead.bfType = 0x4D42;//bmp类型//bfSize是图像文件4个组成部分之和fileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorT ablesize + lineByte*height;fileHead.bfReserved1 = 0;fileHead.bfReserved2 = 0;//bfOffBits是图像文件前三个部分所需空间之和fileHead.bfOffBits=54+colorTablesize;//写文件头进文件fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);//申请位图信息头结构变量,填写信息头信息BITMAPINFOHEADER head;head.biBitCount=biBitCount;head.biClrImportant=0;head.biClrUsed=0;head.biCompression=0;head.biHeight=height;head.biPlanes=1;head.biSize=40;head.biSizeImage=lineByte*height;head.biWidth=width;head.biXPelsPerMeter=0;head.biYPelsPerMeter=0;//写位图信息头进内存fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);//如果灰度图像,有颜色表,写入文件if(biBitCount==8)fwrite(pColorTable, sizeof(RGBQUAD),256, fp);//写位图数据进文件fwrite(imgBuf, height*lineByte, 1, fp);//关闭文件fclose(fp);return 1;}//调色板与灰度图像的关系void main(){//读入指定BMP文件进内存char readPath[]="tarret.BMP";readBmp(readPath);//输出图像的信息printf("width=%d,height=%d,biBitCount=%d\n",bmpWidth,bmpHeight,biBit Count);//改变灰度图像的颜色表蓝色分量的值,察看前后变化if(biBitCount==8){for(int i=0; i<256;i++){pColorTable[i].rgbBlue = 255-pColorTable[i].rgbBlue;}}//将图像数据存盘char writePath[]="tarret1.BMP";saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorT able);//清除缓冲区,pBmpBuf和pColorT able是全局变量,在文件读入时申请的空间delete []pBmpBuf;if(biBitCount==8)delete []pColorTable;}#include"stdio.h"#include"Windows.h"BYTE *pBmpBuf;//读¨¢入¨?图ª?像?数ºy据Y的Ì?指?针?int bmpWidth;//图ª?像?的Ì?宽¨ªint bmpHeight;//图ª?像?的Ì?高?RGBQUAD *pColorTable;//颜?色¦?表À¨ª指?针?int biBitCount;//图ª?像?类¤¨¤型¨ªbool readBmp(char *bmpName){FILE *fp=fopen(bmpName,"rb"); //二t进?制?读¨¢方¤?式º?打䨰开a指?定¡§的Ì?图ª?像?文?件tif(fp==NULL) return 0;fseek(fp, sizeof(BITMAPFILEHEADER),0); //跳¬?过y位?图ª?文?件t头ª¡¤结¨¢构1BITMAPFILEHEADERBITMAPINFOHEADER head; //定¡§义°?位?图ª?信?息¡é头ª¡¤结¨¢构1变À?量¢?,ê?读¨¢取¨?位?图ª?信?息¡é头ª¡¤进?内¨²存ä?,ê?存ä?放¤?在¨²变À?量¢?head中Dfread(&head, sizeof(BITMAPINFOHEADER), 1,fp);bmpWidth = head.biWidth; //获?取¨?图ª?像?宽¨ª、¡é高?、¡é每?像?素?所¨´占?位?数ºy等̨¨信?息¡ébmpHeight = head.biHeight;biBitCount = head.biBitCount;int lByte=(bmpWidth * biBitCount/8+3)/4*4; //定¡§义°?变À?量¢?,ê?计?算?图ª?像?每?行D 像?素?所¨´占?的Ì?字Á?节¨²数ºy/* if(biBitCount==8){pColorTable=new RGBQUAD[256];fread(pColorTable,sizeof(RGBQUAD),256,fp);}*/pBmpBuf=new BYTE[lByte * bmpHeight]; //申¦¨º请?位?图ª?数ºy据Y所¨´需¨¨要°a的Ì?空?间?,ê?读¨¢位?图ª?数ºy据Y进?内¨²存ä?fread(pBmpBuf,1,lByte * bmpHeight,fp);fclose(fp); //关?闭À?文?件treturn 1;}bool saveBmp(char *bmpName, BYTE *imgBuf, int width, int height,int biBitCount, RGBQUAD *pColorTable){if(!imgBuf)return 0;int colorTablesize=0; //颜?色¦?表À¨ª大䨮小?,以°?字Á?节¨²为a单Ì£¤位?,灰¨°度¨¨图ª?像?颜?色¦?表À¨ª为a1024字Á?节¨²,彩¨º色¦?图ª?像?颜?色¦?表À¨ª大䨮小?为a0/* if(biBitCount==8)colorTablesize=1024;*/int lByte=(width * biBitCount/8+3)/4*4; //待äy存ä?储ä¡é图ª?像?数ºy据Y每?行D字Á?节¨²数ºyFILE *fp=fopen(bmpName,"wb"); //以°?二t进?制?写¡ä的Ì?方¤?式º?打䨰开a文?件tif(fp==NULL) return 0;//申¦¨º请?位?图ª?文?件t头ª¡¤结¨¢构1变À?量¢?,ê?填¬?写¡ä文?件t头ª¡¤信?息¡éBITMAPFILEHEADER fileHead;fileHead.bfType = 0x4D42;//bmp类¤¨¤型¨ª//bfSize是º?图ª?像?文?件t4个?组Á¨¦成¨¦部?分¤?之?和¨ªfileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + lByte*height;fileHead.bfReserved1 = 0;fileHead.bfReserved2 = 0;//bfOffBits是º?图ª?像?文?件t前¡ã三¨y个?部?分¤?所¨´需¨¨空?间?之?和¨ªfileHead.bfOffBits=54+colorTablesize;fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp); //写¡ä文?件t头ª¡¤进?文?件tBITMAPINFOHEADER head; //申¦¨º请?位?图ª?信?息¡é头ª¡¤结¨¢构1变À?量¢?,ê?填¬?写¡ä信?息¡é头ª¡¤信?息¡éhead.biBitCount=biBitCount;head.biClrImportant=0;head.biClrUsed=0;head.biCompression=0;head.biHeight=height;head.biPlanes=1;head.biSize=40;head.biSizeImage=lByte*height;head.biWidth=width;head.biXPelsPerMeter=0;head.biYPelsPerMeter=0;fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp); //写¡ä位?图ª?信?息¡é头ª¡¤进?内¨²存ä? fwrite(imgBuf, height*lByte, 1, fp); //写¡ä位?图ª?数ºy据Y进?文?件tfclose(fp); //关?闭À?文?件treturn 1;}bool rgb_to_yuv(BYTE *imgBuf, int width, int height){int i=0,j=0;for( i=0;i< height;i++ ){for( j=0;j<width;j++ ){int pos = width * i + j; // 像?素?点Ì?位?置?BYTE B = imgBuf[pos*3];BYTE G = imgBuf[pos*3+1];BYTE R = imgBuf[pos*3+2];BYTE Y= (BYTE)(0.3*R + 0.59*G + 0.11*B);BYTE U= (BYTE)((B-Y) * 0.493);BYTE V= (BYTE)((R-Y) * 0.877);Y=Y+10;B= (BYTE)(Y + 2.032*U);G= (BYTE)(Y - 0.394*U - 0.581*V);R= (BYTE)(Y + 1.140*V);imgBuf[pos*3]=B;imgBuf[pos*3+1]=G;imgBuf[pos*3+2]=R;}}return 1;}void main(int argc,char *argv[]){char readPath[]="C:\\1.BMP";readBmp(readPath); //读¨¢入¨?指?定¡§BMP文?件tprintf("width=%d,height=%d,biBitCount=%d\n",bmpWidth,bmpHeight,biBitCount); //输º?出?图ª?像?的Ì?信?息¡échar writePath[]="C:\\tarret1.BMP"; //将?图ª?像?数ºy据Y存ä?盘¨¬saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);delete []pBmpBuf; //清?除y缓o冲?区?,ê?pBmpBuf和¨ªpColorTable是º?全¨?局?变À?量¢?,ê?在¨²文?件t读¨¢入¨?时º¡À申¦¨º请?的Ì?空?间?if(biBitCount==8)delete []pColorTable;scanf("%d");}。