2012-07-22 85 views
0

我寫這個簡單的代碼保存位圖文件(* .BMP)從HWND。Get和從HWND(8,4,1位每像素 - 黑色圖像)保存位圖

#include <stdio.h> 
#include <windows.h> 

bool captureAndSave(const HWND& hWnd, int nBitCount, const char* szFilePath) 
{ 
    if(!szFilePath || !strlen(szFilePath)) 
    { 
     printf("bad function arguments\n"); 
     return false; 
    } 

    //calculate the number of color indexes in the color table 
    int nColorTableEntries = -1; 
    switch(nBitCount) 
    { 
     case 1: 
      nColorTableEntries = 2; 
      break; 
     case 4: 
      nColorTableEntries = 16; 
      break; 
     case 8: 
      nColorTableEntries = 256; 
      break; 
     case 16: 
     case 24: 
     case 32: 
      nColorTableEntries = 0; 
      break; 
     default: 
      nColorTableEntries = -1; 
      break; 
    } 

    if(nColorTableEntries == -1) 
    { 
     printf("bad bits-per-pixel argument\n"); 
     return false; 
    } 

    HDC hDC = GetDC(hWnd); 
    HDC hMemDC = CreateCompatibleDC(hDC); 

    int nWidth = 0; 
    int nHeight = 0; 

    if(hWnd != HWND_DESKTOP) 
    { 
     RECT rect; 
     GetClientRect(hWnd, &rect); 
     nWidth = rect.right - rect.left; 
     nHeight = rect.bottom - rect.top; 
    } 
    else 
    { 
     nWidth = ::GetSystemMetrics(SM_CXSCREEN); 
     nHeight = ::GetSystemMetrics(SM_CYSCREEN); 
    } 


    HBITMAP hBMP = CreateCompatibleBitmap(hDC, nWidth, nHeight); 
    SelectObject(hMemDC, hBMP); 
    BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY); 

    int nStructLength = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries; 
    LPBITMAPINFOHEADER lpBitmapInfoHeader = (LPBITMAPINFOHEADER)new char[nStructLength]; 
    ::ZeroMemory(lpBitmapInfoHeader, nStructLength); 

    lpBitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER); 
    lpBitmapInfoHeader->biWidth = nWidth; 
    lpBitmapInfoHeader->biHeight = nHeight; 
    lpBitmapInfoHeader->biPlanes = 1; 
    lpBitmapInfoHeader->biBitCount = nBitCount; 
    lpBitmapInfoHeader->biCompression = BI_RGB; 
    lpBitmapInfoHeader->biXPelsPerMeter = 0; 
    lpBitmapInfoHeader->biYPelsPerMeter = 0; 
    lpBitmapInfoHeader->biClrUsed = nColorTableEntries; 
    lpBitmapInfoHeader->biClrImportant = nColorTableEntries; 

    DWORD dwBytes = ((DWORD) nWidth * nBitCount)/32; 
    if(((DWORD) nWidth * nBitCount) % 32) { 
     dwBytes++; 
    } 
    dwBytes *= 4; 

    DWORD dwSizeImage = dwBytes * nHeight; 
    lpBitmapInfoHeader->biSizeImage = dwSizeImage; 

    LPBYTE lpDibBits = 0; 
    HBITMAP hBitmap = ::CreateDIBSection(hMemDC, (LPBITMAPINFO)lpBitmapInfoHeader, DIB_RGB_COLORS, (void**)&lpDibBits, NULL, 0); 
    SelectObject(hMemDC, hBitmap); 
    BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY); 
    ReleaseDC(hWnd, hDC); 

    BITMAPFILEHEADER bmfh; 
    bmfh.bfType = 0x4d42; // 'BM' 
    int nHeaderSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries; 
    bmfh.bfSize = 0; 
    bmfh.bfReserved1 = bmfh.bfReserved2 = 0; 
    bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries;  

    FILE *pFile = 0; 
    fopen_s(&pFile, szFilePath, "wb"); 
    if(!pFile) 
    { 
     ::DeleteObject(hBMP); 
     ::DeleteObject(hBitmap); 
     delete[]lpBitmapInfoHeader; 
     printf("can not open file\n"); 
     return false; 
    } 

    DWORD nColorTableSize = 0; 
    if (nBitCount != 24) 
     nColorTableSize = (1 << nBitCount) * sizeof(RGBQUAD); 
    else 
     nColorTableSize = 0; 


    fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, pFile); 
    fwrite(lpBitmapInfoHeader, nHeaderSize,1,pFile); 

    if(nBitCount < 16) 
    { 
     int nBytesWritten = 0; 
     RGBQUAD *rgbTable = new RGBQUAD[nColorTableEntries * sizeof(RGBQUAD)]; 
     //fill RGBQUAD table and write it in file 
     for(int i = 0; i < nColorTableEntries; ++i) 
     { 
      rgbTable[i].rgbRed = rgbTable[i].rgbGreen = rgbTable[i].rgbBlue = i; 
      rgbTable[i].rgbReserved = 0; 

      fwrite(&rgbTable[i], sizeof(RGBQUAD), 1, pFile); 
     } 
     delete[]rgbTable; 

     /* 
     RGBQUAD rgb; 
     for (DWORD i = 0; i < nColorTableEntries ; i++) 
     { 
      rgb.rgbBlue = rgb.rgbGreen = rgb.rgbRed = (BYTE)(i*(255/(nColorTableEntries-1))); 
      nBytesWritten = fwrite(&rgb, 1, sizeof(rgb), pFile); 
      if (nBytesWritten != sizeof(rgb)) 
      { 
       printf("error while writing rgb header\n"); 
       fclose(pFile); 

       ::DeleteObject(hBMP); 
       ::DeleteObject(hBitmap); 
       delete[]lpBitmapInfoHeader; 

       return false; 
      } 
     } 
     */ 
    } 

    fwrite(lpDibBits, dwSizeImage, 1, pFile); 

    fclose(pFile); 

    ::DeleteObject(hBMP); 
    ::DeleteObject(hBitmap); 
    delete[]lpBitmapInfoHeader; 
} 

int main(int argc, char **argv) 
{ 
    captureAndSave(HWND_DESKTOP, 1, "1.bmp"); 
    captureAndSave(HWND_DESKTOP, 4, "4.bmp"); 
    captureAndSave(HWND_DESKTOP, 8, "8.bmp"); 
    captureAndSave(HWND_DESKTOP, 16, "16.bmp"); 
    captureAndSave(HWND_DESKTOP, 24, "24.bmp"); 
    captureAndSave(HWND_DESKTOP, 32, "32.bmp"); 

    return 0; 
} 

圖像被正確保存爲每像素32位,24位和16位。但是,對於每個像素8位,4位和1位僅包含黑色像素。

請告訴我我做錯了什麼。

+0

爲什麼你會碰到中間HDC?這似乎是浪費,只是增加了一個潛在的錯誤向量。您似乎也會爲24以外的所有位深生成顏色表。 – 2012-07-23 06:04:37

回答

1

當GDI副本圖像索引表面,它需要它具有的顏色映射源到目的地可用的顏色上。

直到,除非你創建並選擇一個調色板到目標DC中,否則GDI將不知道可用的顏色,並且將使用默認調色板來映射顏色,該調色板將僅定義黑色和白色。

的可能是相當參與這個有很多 - 最好你要掃描的源圖像,創建地圖使用的所有顏色及其freqencies,並用它來計算理想的調色板。

或者,只是使用CreateHalfTonePalette

在你的情況,你是塊傳輸到與所需的位深一個DIBSection,所以你需要在執行的blit前初始化DIBSections色表。 IIRC,當位圖傳輸到一個DIB組中,具有DIBSections顏色表設置比選擇HPALETTE到DC更重要 - 但可以使用通過CreateHalfTonePalette創建的調色板,並提取所得的顏色表。

1

對於8/4/1位圖像,這是索引圖像,必須寫RGBQUAD表文件,因爲原始的位圖數據不是顏色,而是索引RQBQUAD表。

+0

感謝您的回覆。現在我正在寫RGBQUAD表(見代碼),但我仍然有8/4/1位圖像中的黑色像素。 – silverrulezz 2012-07-22 17:37:13