原创 VC将HBITMAP转换成BMP位图文件的各个部分,可以在1BIT,4BIT,8BIT,16BIT,

2009-11-1 19:58 7404 11 11 分类: 工程师职场

VCHBITMAP转换成BMP位图文件的各个部分,可以在1BIT,4BIT,8BIT,16BIT,24BIT,32BIT之间转换<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


 


2009.9.23


经过这段时间的努力,终于在VC下做成功了,将HBITMAP转换成BMP位图文件的各个部分,可以在1BIT,4BIT,8BIT,16BIT,24BIT,32BIT之间转换,但不能在彩色和灰度之间转换。


GetDIBits()理解和试验了很多次。个人认为GetDIBits()需要HCD参数,可能是因为它需要HCD来做一些转换工作,但它又没有申请HCD,所以需要程序给它一个HCD


 


改自MSDN2001,程序如下:


 


 


///////////////////////////////////////////////////////////////////////////////////////////////////////


BOOL  myCreateBitmap( HDC hDC,  HBITMAP hbitmap, int pixbit,


PBITMAPFILEHEADER &outheadbuf,long *outheadsize,


PBITMAPINFO &outinfobuf,long *outinfosize,


LPBYTE &outdatabuf,long *outdatasize)


//我:根据HDCHBITMP,及自定义的"每像素比特数",来建立文件头、信息头、位图数据(改自MSDN


//pixbit 是自定义的每像素BIT  (如果为0,则按HBITMAP里的不变)


//输入hDC, hbitmap, pixbit


//输出文件头指针,文件头字节数,信息指针,信息字节数,位图数据指针,位图数据字节数


//函数会GlobalAlloc申请内存,主程序不用申请内存,但要GlobalFree掉内存


//成功时返回TRUE


{


BITMAP bmp;


WORD cClrBits;


DWORD my_biClrUsed=0;


outinfobuf=NULL;


outdatabuf=NULL;


outheadbuf=NULL;


if(pixbit!=0 && pixbit!=32 && pixbit!=24 && pixbit!=16 && pixbit!=8 && pixbit!=4 && pixbit!=1) goto errout;


 // Retrieve the bitmap's color format, width, and height. 得到HBITMAP的信息


if (!GetObject(hbitmap, sizeof(BITMAP), (LPSTR)&bmp))   goto errout;


if (pixbit)   //强制转换的位数


 {bmp.bmPlanes=1;  bmp.bmBitsPixel=pixbit; } //强制赋值转换出来的每像素BIT


 // Convert the color format to a count of bits.


 cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);  //得到每像素多少位


 if (cClrBits == 1)        cClrBits = 1;


 else if (cClrBits <= 4)   cClrBits = 4;


 else if (cClrBits <= 8)   cClrBits = 8;


 else if (cClrBits <= 16)  cClrBits = 16;


 else if (cClrBits <= 24)  cClrBits = 24;


 else                      cClrBits = 32;


 // Allocate memory for the BITMAPINFO structure. (This structure


 // contains a BITMAPINFOHEADER structure and an array of RGBQUAD


 // data structures.)


  if (cClrBits != 24)


       {


   *outinfosize= sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits);


   outinfobuf = (PBITMAPINFO) GlobalAlloc (GPTR,   *outinfosize);


                                 //分配内存大小,信息头+调色板大小


    // There is no RGBQUAD array for the 24-bit-per-pixel format.


       }


  else //24BIT的,没有调色板


       {


   *outinfosize= sizeof(BITMAPINFOHEADER);


   outinfobuf = (PBITMAPINFO) GlobalAlloc (GPTR,  *outinfosize);


}


 // Initialize the fields in the BITMAPINFO structure.


 outinfobuf->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //信息头大小(不含调色板)


 outinfobuf->bmiHeader.biWidth = bmp.bmWidth;


 outinfobuf->bmiHeader.biHeight = bmp.bmHeight;


 outinfobuf->bmiHeader.biPlanes = bmp.bmPlanes;


 outinfobuf->bmiHeader.biBitCount = bmp.bmBitsPixel;


 if (cClrBits < 24) 


 {


  my_biClrUsed=(1<<cClrBits); 


  outinfobuf->bmiHeader.biClrUsed = my_biClrUsed;


 }    //位图实际使用的彩色表中的颜色索引数


 // If the bitmap is not compressed, set the BI_RGB flag.


 outinfobuf->bmiHeader.biCompression = BI_RGB;


 // Compute the number of bytes in the array of color


 // indices and store the result in biSizeImage.


 // For Windows NT/2000, the width must be DWORD aligned unless


 // the bitmap is RLE compressed. This example shows this.


 // For Windows 95/98, the width must be WORD aligned unless the


 // bitmap is RLE compressed.


 outinfobuf->bmiHeader.biSizeImage = ((outinfobuf->bmiHeader.biWidth * cClrBits +31) & ~31)\


         /8 * outinfobuf->bmiHeader.biHeight;


        //图像大小


 // Set biClrImportant to 0, indicating that all of the


 // device colors are important.


  outinfobuf->bmiHeader.biClrImportant = 0;


 


/////////////////////////////////得到位图数据


// GlobalAlloc分配位图数据的内存


// GetDIBits 根据hDC HBITMAP得到位图数据、调色板数据


*outdatasize=outinfobuf->bmiHeader.biSizeImage;


outdatabuf = (LPBYTE) GlobalAlloc(GPTR,    *outdatasize);  //根据位图大小分配内存


if (!outdatabuf)    goto errout;


 // Retrieve the color table (RGBQUAD array) and the bits


 // (array of palette indices) from the DIB.


if (!GetDIBits(    //根据DCBITMAP得到位图数据


    hDC,


    hbitmap,


    0,


    (WORD) outinfobuf->bmiHeader.biHeight,


    outdatabuf,     // outdatabuf中得到位图数据


    outinfobuf,     


    DIB_RGB_COLORS) )


 {  goto errout;  }


//注意:GetDIBits()会更改outinfobuf->bmiHeader.biClrUsed值为0,使后面


//分配内存时大小不正确,导致生成的BMP文件有问题!!!


//因此,前面引入变量my_biClrUsed来事先保存outinfobuf->bmiHeader.biClrUsed


//后面的分配内存时,使用my_biClrUsed来计算和分配


//如果有调色板,则GetDIBits()会将调色板数据放到outinfobuf指定的信息头的后面。


//对于16bpp,调色板共有65536×4字节。位图数据中,每个像素是2字节,最高位是0


//对于16bppGetDIBits不会改变调色板数据,如果outinfobuff+40开始,是非0,则调用完GetDIBits后,仍是非0


//说明对于16bpp,调色板是没有用处的。经实验,无论是选DIB_RGB_COLORS,还是选DIB_PAL_COLORSGetDIBits都没有调色板数据输出,也不会更改内存中的调色板数据,并且得到的位图数据和位图文件都是一样的。


//对于16bpp,即使调色板数据非0ACDSEE打开BMP文件也不会用到调色板数据,只会用到位图数据部分。


//biCompression等于BI_RGB时,位图数据是RGB555 for 16bpp(最高位是0 and RGB888 for 32bpp(最高字节是0


//对于8bpp,如果参数是DIB_PAL_COLORS,则生成的是每个颜色16bits2个字节)的调色板,8bpp就是256个颜色,在内存中是


//这些数值:0x00 00 01 00 02 00 03 00 04 00 ....一直到0xFE 00 FF 00。说明这16比特是索引到当前逻辑调色板的索引值


//而位图数据则是对应了这些索引值的值!


//对于1bpp,如果参数是DIB_RGB_COLORS,会生成调色板数据,是2个颜色,4×2个字节,即是0x00 00 00 00 ff ff ff 00


//对于1bpp,如果参数是DIB_PAL_COLORS,会生成调色板数据,是2个颜色,2×2个字节,即是0x00 00 01 00


 


 


/////////////////////////////////得到文件头


*outheadsize= sizeof(BITMAPFILEHEADER);


outheadbuf = (PBITMAPFILEHEADER) GlobalAlloc(GPTR,  *outheadsize);


//根据位图大小分配内存


if (!outheadbuf)    goto errout;


 outheadbuf->bfType = 0x4d42;  // 0x42 = "B" 0x4d = "M"


       // Compute the size of the entire file.


 outheadbuf->bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + \


                          outinfobuf->bmiHeader.biSize +\


                          my_biClrUsed * sizeof(RGBQUAD) +\


                          outinfobuf->bmiHeader.biSizeImage);


 outheadbuf->bfReserved1 = 0;


 outheadbuf->bfReserved2 = 0;


      // Compute the offset to the array of color indices.


 outheadbuf->bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +


                    outinfobuf->bmiHeader.biSize +\


                    my_biClrUsed * sizeof (RGBQUAD);


return TRUE;


 


//////////////////////错误处理


errout:


if(outinfobuf) GlobalFree(outinfobuf);


if(outdatabuf) GlobalFree(outdatabuf);


if(outheadbuf) GlobalFree(outheadbuf);


outinfobuf=NULL;


outdatabuf=NULL;


outheadbuf=NULL;


*outheadsize=0;


*outinfosize=0;


*outdatasize=0;


return FALSE;


 


}


 


 


 


 


使用方法如下:


/////////////////////////////////////////////////////


void CTestDlg::OnButton8()


{


HBITMAP bitmap;


CString cst;


CFile DownloadFile;


/////读取位图文件SAMPLE.BMP


bitmap=(HBITMAP)LoadImage(AfxGetInstanceHandle(),"sample.BMP",IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);


ASSERT(bitmap);


HDC hDC;


PBITMAPFILEHEADER outheadbuf;


PBITMAPINFO outinfobuf;


LPBYTE outdatabuf;


long outheadsize,outinfosize,outdatasize;


hDC = ::GetDC(NULL);


if (!myCreateBitmap( hDC,  bitmap, 8,


    outheadbuf,&outheadsize,


    outinfobuf,&outinfosize,


    outdatabuf,&outdatasize) )


{


 MessageBox("error"); goto errout;


}


DownloadFile.Open("c:\\out.bmp",CFile::modeCreate | CFile::modeWrite);


DownloadFile.Write(outheadbuf,outheadsize);


DownloadFile.Write(outinfobuf,outinfosize);


DownloadFile.Write(outdatabuf,outdatasize);


DownloadFile.Close();


MessageBox("ok");


if(outinfobuf) GlobalFree(outinfobuf);


if(outdatabuf) GlobalFree(outdatabuf);


if(outheadbuf) GlobalFree(outheadbuf);


 


errout:


 ::ReleaseDC(NULL,hDC);


}


 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
11
关闭 站长推荐上一条 /3 下一条