int iPixel  = 24;
HANDLE hp; BITMAP bmpScreen; // Get the BITMAP from the HBITMAP
GetObject(hBitmap,sizeof(BITMAP),&bmpScreen); //图形格式参数
BITMAPFILEHEADER   bmfHeader;    
BITMAPINFOHEADER   bi; bi.biSize = sizeof(BITMAPINFOHEADER);    
bi.biWidth = bmpScreen.bmWidth;    
bi.biHeight = bmpScreen.bmHeight;  
bi.biPlanes = 1;    
bi.biBitCount = iPixel;    
bi.biCompression = BI_RGB;    
bi.biSizeImage = 0;  
bi.biXPelsPerMeter = 0;    
bi.biYPelsPerMeter = 0;    
bi.biClrUsed = 0;    
bi.biClrImportant = 0; DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight; // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that 
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc 
// have greater overhead than HeapAlloc.
HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize+sizeof(BITMAPINFOHEADER)); 
LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);    
*lpbi = bi;
// Gets the "bits" from the bitmap and copies them into a buffer 
// which is pointed to by lpbi
GetDIBits(hMemDC,hBitmap,0,
(UINT)bmpScreen.bmHeight, 
lpbi,
(BITMAPINFO *)lpbi, DIB_RGB_COLORS);  
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); //Offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);  //Size of the file
bmfHeader.bfSize = dwSizeofDIB;  //bfType must always be BM for Bitmaps
bmfHeader.bfType = 0x4D42; //BM    if(file.Open(szBMPFileName,CFile::modeWrite | CFile::modeCreate))
{
file.Write(&bmfHeader,sizeof(BITMAPFILEHEADER));
file.Write(&bi,sizeof(BITMAPINFOHEADER));
file.Write(lpbi,dwBmpSize);   
                 
file.Close();
}以上代码能正确保存为BMP文件!红色处不明白,还请教!
lpbi中已包含有信息头,位图信息头为什么要写两次到BMP文件中呢?

解决方案 »

  1.   

    *lpbi = bi; //是将bi里面的值复制到lpbi指针空间!
    file.Write(&bi,sizeof(BITMAPINFOHEADER)); //将bmp写到文件,这是写bmp的文件头部!
    file.Write(lpbi,dwBmpSize);   //具体的内容!
      

  2.   

    file.Write(lpbi,dwBmpSize);  //具体的内容!
    lpbi指的内存中,不是已经包含有位图信息头了吗?就是包含过BITMAPINFOHEADER,为什么写两次呢?
      

  3.   

    file.Write(&bi,sizeof(BITMAPINFOHEADER)); 
    这个没有写内容,写的是BMP头部,sizeof(BITMAPINFOHEADER)只有40字节!
      

  4.   

    明白楼上所说的,file.Write(&bi,sizeof(BITMAPINFOHEADER)); 是写BMP的头部,
                   file.Write(lpbi,dwBmpSize);  //具体的内容!是写具体内容,
        现在问题是我发现,lpbi具体内容存储空间的前40字节,已经是BMP头部的,这两行代码等于把头总信息写了两次到BMP文件中!
         这个问题是不是和   GetDIBits(hMemDC,hBitmap,0,(UINT)bmpScreen.bmHeight, lpbi, 
    (BITMAPINFO *)lpbi, DIB_RGB_COLORS);  有关?
      

  5.   

    或是GetDIBits()方法把bitmap图像数据按位读到lpbi所指空间时,又把前 40字节覆盖了?(*lpbi = bi; ) 些句在GetDIBits()方法前,bi就是头部信息!
      

  6.   

    int GetDIBits(
      HDC hdc,           // handle to device context
      HBITMAP hbmp,      // handle to bitmap
      UINT uStartScan,   // first scan line to set in destination bitmap
      UINT cScanLines,   // number of scan lines to copy
      LPVOID lpvBits,    // address of array for bitmap bits
      LPBITMAPINFO lpbi, // address of structure with bitmap data
      UINT uUsage        // RGB or palette index
    );
    看楼主对这个函数的用法,那习惯不是一种好的习惯,其结果之一就像现有楼主的疑惑一样就产生了。倒数第二个参数lpbi是一个信息结构体指针,它指明了要获取到的BMP数据格式,而倒数第三个则是保存获取到的DIB数据。楼主把这两个参数用同一变量,虽然在调用该函数之前,对lpbi进行了附值,但在函数返回之后,里面的内容即被破坏掉,因为它被DIB数据覆盖掉了。所以楼主可以跟踪一下,在调用返回之后,你的lpbi里的内容,还是不是你在调用之前附值之后的那些东西,肯定不是!a
      

  7.   

    typedef struct tagBITMAPINFO { 
      BITMAPINFOHEADER bmiHeader; 
      RGBQUAD          bmiColors[1]; 
    } BITMAPINFO, *PBITMAPINFO; 
    BITMAPINFO内含有头部信息!所以,在GetDIBits中,(BITMAPINFO *)lpbi算输入与输出参数吧,输入的是BITMAPINFOHEADER ,然后,输出的是RGBQUAD!应该是这样的!
    建议楼主调试跟踪一下看看!还有,建议楼主把前面的几个文件头部去掉看看是否可以!我也觉的多写了!
      

  8.   

    刚跟踪了下,信息头中前后只有 bi.biSizeImage = 0;  变了,调用后,bi.biSizeImage 变成很大的值,是图像字节大小,信息头的前六个变量值还一样!
     楼上的,我也试过, file.Write(&bmfHeader,sizeof(BITMAPFILEHEADER)); 
                      file.Write(&bi,sizeof(BITMAPINFOHEADER)); 
                      file.Write(lpbi,dwBmpSize);  
    第二行是不能去的,去掉,就保存失败了!去掉换成下面的,能保存成功,不过图片打开后,颜色发生变化了!
                  file.Write(&bmfHeader,sizeof(BITMAPFILEHEADER));
    //file.Write(&bi,sizeof(BITMAPINFOHEADER));
    file.Write(lpbi,dwBmpSize + sizeof(BITMAPINFOHEADER) );
      

  9.   

    BMP文件组成部分包含:BMP文件头结构,位图信息头结构,位图颜色表,位图像素数据,而DIB位图数据本身还包含有位图信息头结构,它里面biSizeImage为图像字节数!不知这样的理解正确否?还请教!
      

  10.   

    int GetDIBits( 
      HDC hdc,          // handle to device context 
      HBITMAP hbmp,      // handle to bitmap 
      UINT uStartScan,  // first scan line to set in destination bitmap 
      UINT cScanLines,  // number of scan lines to copy 
      LPVOID lpvBits,    // address of array for bitmap bits 
      LPBITMAPINFO lpbi, // address of structure with bitmap data 
      UINT uUsage        // RGB or palette index 
    ); 
    看楼主对这个函数的用法,那习惯不是一种好的习惯,其结果之一就像现有楼主的疑惑一样就产生了。倒数第二个参数lpbi是一个信息结构体指针,它指明了要获取到的BMP数据格式,而倒数第三个则是保存获取到的DIB数据。楼主把这两个参数用同一变量,虽然在调用该函数之前,对lpbi进行了附值,但在函数返回之后,里面的内容即被破坏掉,因为它被DIB数据覆盖掉了。所以楼主可以跟踪一下,在调用返回之后,你的lpbi里的内容,还是不是你在调用之前附值之后的那些东西,肯定不是!a是这样的!
      

  11.   

    GetDIBits(hMemDC,hBitmap,0, 
    (UINT)bmpScreen.bmHeight, 
    lpbi, 
    (BITMAPINFO *)lpbi, DIB_RGB_COLORS);  这里笔误吧,导致写成红色字那样.应该是:
    GetDIBits(hMemDC,hBitmap,0, 
    (UINT)bmpScreen.bmHeight, 
    lpbi+sizeof(BITMAPINFOHEADER), 
    (BITMAPINFO *)lpbi, DIB_RGB_COLORS);  那么就直接可以:
    if(file.Open(szBMPFileName,CFile::modeWrite | CFile::modeCreate)) 

    file.Write(&bmfHeader,sizeof(BITMAPFILEHEADER)); 
    //file.Write(&bi,sizeof(BITMAPINFOHEADER)); 
    file.Write(lpbi,dwBmpSize+sizeof(BITMAPINFOHEADER));                  
    file.Close(); 
      

  12.   

    楼上的代码我也试过,这样话,保存,颜色都正确,但出现图片左右倒置现像,原代码是正确的,能正确保存,是MSDN上的例子一部分!