2015-10-01 32 views
0

它會寫入我的BITMAP.bmp文件,但是當我嘗試在Windows照片查看器中查看時它說「Windows照片查看器無法打開此圖片,因爲文件看起來已損壞,損壞或太大了。「我知道我應該把這些功能放到頭文件中,但是我從來沒有真正深入到一個項目中來真正製作頭文件,所以我忘記了它的方式。如果有人知道Windows照片查看器中圖片的大小限制,我將非常感謝。我從MSDN中獲得了一些這些功能(毫不羞恥)。錯誤處理可能會更好,但我沒有errorhandler.h。我不完全確定所有的功能是如何工作的,因爲正如我所說我使用了MSDN的一些代碼。 我會非常感謝任何人可以幫助我。 :)在winapi中保存位圖問題

#include <errorrep.h> 
#include <windows.h> 
#include <iostream> 
using namespace std; 

namespace Globals{ 
    HBITMAP hBitmap; 
    HDC hScreen; 
} 
using namespace Globals; 

void GetScreenShot(void) 
{ 
    int x1, y1, x2, y2, w, h; 
    LPSIZE lpSize; 
    LPVOID lpvBits; 
    // get screen dimensions 
    x1 = GetSystemMetrics(SM_XVIRTUALSCREEN); 
    x2 = GetSystemMetrics(SM_CXVIRTUALSCREEN); 
    y1 = GetSystemMetrics(SM_YVIRTUALSCREEN); 
    y2 = GetSystemMetrics(SM_CYVIRTUALSCREEN); 
    w = x2-x1; 
    h = y2-y1; 

    // copy screen to bitmap 
    hScreen = GetDC(NULL); 
    HDC  hDC  = CreateCompatibleDC(hScreen); 
    hBitmap = CreateCompatibleBitmap(hScreen, w, h); 
    HGDIOBJ old_obj = SelectObject(hDC, hBitmap); 
    BOOL bRet = BitBlt(hDC, 0, 0, w, h, hScreen, x1, y1, SRCCOPY); 
    GetBitmapDimensionEx(hBitmap, lpSize); 
    GetBitmapBits(hBitmap, (LONG)lpSize, lpvBits); 
    // save bitmap to clipboard 
    OpenClipboard(NULL); 
    EmptyClipboard(); 
    SetClipboardData(CF_BITMAP, hBitmap); 
    CloseClipboard(); 
    // clean up 
    SelectObject(hDC, old_obj); 
    /*DeleteDC(hDC); 
    ReleaseDC(NULL, hScreen); 
    DeleteObject(hBitmap);*/ 
} 

PBITMAPINFO CreateBitmapInfoStruct(/*HWND hwnd, */HBITMAP hBmp) 
{ 
    BITMAP bmp; 
    PBITMAPINFO pbmi; 
    WORD cClrBits; 

    // Retrieve the bitmap color format, width, and height. 
    if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp)) 
     //errhandler("GetObject", hwnd); 
     cout << "Error: CreateBitmapInfoStruct" << endl; 

    // 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) 
     pbmi = (PBITMAPINFO) LocalAlloc(LPTR, 
        sizeof(BITMAPINFOHEADER) + 
        sizeof(RGBQUAD) * (1<< cClrBits)); 

    // There is no RGBQUAD array for these formats: 24-bit-per-pixel or 32-bit-per-pixel 

    else 
     pbmi = (PBITMAPINFO) LocalAlloc(LPTR, 
        sizeof(BITMAPINFOHEADER)); 

    // Initialize the fields in the BITMAPINFO structure. 

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    pbmi->bmiHeader.biWidth = bmp.bmWidth; 
    pbmi->bmiHeader.biHeight = bmp.bmHeight; 
    pbmi->bmiHeader.biPlanes = bmp.bmPlanes; 
    pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; 
    if (cClrBits < 24) 
     pbmi->bmiHeader.biClrUsed = (1<<cClrBits); 

    // If the bitmap is not compressed, set the BI_RGB flag. 
    pbmi->bmiHeader.biCompression = BI_RGB; 

    // Compute the number of bytes in the array of color 
    // indices and store the result in biSizeImage. 
    // The width must be DWORD aligned unless the bitmap is RLE 
    // compressed. 
    pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 
            * pbmi->bmiHeader.biHeight; 
    // Set biClrImportant to 0, indicating that all of the 
    // device colors are important. 
    pbmi->bmiHeader.biClrImportant = 0; 
    return pbmi; 
} 

void CreateBMPFile(/*HWND hwnd, */LPTSTR pszFile, PBITMAPINFO pbi, 
        HBITMAP hBMP, HDC hDC) 
{ 
    HANDLE hf;     // file handle 
    BITMAPFILEHEADER hdr;  // bitmap file-header 
    PBITMAPINFOHEADER pbih;  // bitmap info-header 
    LPBYTE lpBits;    // memory pointer 
    DWORD dwTotal;    // total count of bytes 
    DWORD cb;     // incremental count of bytes 
    BYTE *hp;     // byte pointer 
    DWORD dwTmp; 

    pbih = (PBITMAPINFOHEADER) pbi; 
    lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage); 

    if (!lpBits) 
     //errhandler("GlobalAlloc", hwnd); 
     cout << "!lpBits" << endl; 
    // Retrieve the color table (RGBQUAD array) and the bits 
    // (array of palette indices) from the DIB. 
    if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi, 
     DIB_RGB_COLORS)) 
    { 
     //errhandler("GetDIBits", hwnd); 
     cout << "Error 1" << endl; 
    } 

    // Create the .BMP file. 
    hf = CreateFile(pszFile, 
        GENERIC_READ | GENERIC_WRITE, 
        (DWORD) 0, 
        NULL, 
        CREATE_ALWAYS, 
        FILE_ATTRIBUTE_NORMAL, 
        (HANDLE) NULL); 
    if (hf == INVALID_HANDLE_VALUE) 
     //errhandler("CreateFile", hwnd); 
    hdr.bfType = 0x4d42;  // 0x42 = "B" 0x4d = "M" 
    // Compute the size of the entire file. 
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + 
       pbih->biSize + pbih->biClrUsed 
       * sizeof(RGBQUAD) + pbih->biSizeImage); 
    hdr.bfReserved1 = 0; 
    hdr.bfReserved2 = 0; 

    // Compute the offset to the array of color indices. 
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + 
        pbih->biSize + pbih->biClrUsed 
        * sizeof (RGBQUAD); 

    // Copy the BITMAPFILEHEADER into the .BMP file. 
    if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), 
     (LPDWORD) &dwTmp, NULL)) 
    { 
     //errhandler("WriteFile", hwnd); 
     cout << "!WriteFile" << endl; 
    } 

    // Copy the BITMAPINFOHEADER and RGBQUAD array into the file. 
    if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) 
        + pbih->biClrUsed * sizeof (RGBQUAD), 
        (LPDWORD) &dwTmp, (NULL))) 
     //errhandler("WriteFile", hwnd); 
     cout << "!WriteFile" << endl; 

    // Copy the array of color indices into the .BMP file. 
    dwTotal = cb = pbih->biSizeImage; 
    hp = lpBits; 
    if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL)) 
      //errhandler("WriteFile", hwnd); 
      cout << "if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))" << endl; 

    // Close the .BMP file. 
    if (!CloseHandle(hf)) 
      //errhandler("CloseHandle", hwnd); 

    // Free memory. 
    GlobalFree((HGLOBAL)lpBits); 
} 

int main() { 
    cout << "ScreenShot - Takes a screen shot\nScreen shot will be put in your clipboard" 
    "\nThere will be 10 seconds before it takes the screen shot\n" << endl; 
    string input; 
    do 
    { 
     cin >> input; 

     if(input == "ScreenShot") 
     { 
      /*for(int i=1; i<11; i++) 
      { 
       Sleep(1000); 
       cout << i << endl; 
       if(i == 10) 
       { 
        break; 
       } 
      }*/ 
      GetScreenShot(); 
      PBITMAPINFO pbmi = CreateBitmapInfoStruct(hBitmap); 
      CreateBMPFile("C:\\Users\\Owner\\Desktop\\BITMAP.bmp", pbmi, hBitmap, hScreen); 
      cout << "ScreenShot taken!" << endl; 
      cin.ignore(2); 
      Sleep(3000); 
      break; 
     } 
     else 
     { 
      cout << "Invalid command." << endl; 
     } 

    } while(true); 

    return 0; 
} 
+0

你的目標是?你想拍攝屏幕截圖並保存到文件?你想使用'HBITMAP'並保存到文件嗎?你想繪製並保存到文件?你想操縱位,然後保存到文件? –

+0

我只是想截圖並將其保存到文件。 –

+0

也許這將有助於http://stackoverflow.com/a/30114983/4603670 –

回答

3

傳遞初始化值GetBitmapDimensionExGetBitmapBits似乎並不好,所以刪除它們,因爲他們似乎並沒有被使用。

void GetScreenShot(void) 
{ 
    int x1, y1, x2, y2, w, h; 
    // get screen dimensions 
    x1 = GetSystemMetrics(SM_XVIRTUALSCREEN); 
    x2 = GetSystemMetrics(SM_CXVIRTUALSCREEN); 
    y1 = GetSystemMetrics(SM_YVIRTUALSCREEN); 
    y2 = GetSystemMetrics(SM_CYVIRTUALSCREEN); 
    w = x2-x1; 
    h = y2-y1; 

    // copy screen to bitmap 
    hScreen = GetDC(NULL); 
    HDC  hDC  = CreateCompatibleDC(hScreen); 
    hBitmap = CreateCompatibleBitmap(hScreen, w, h); 
    HGDIOBJ old_obj = SelectObject(hDC, hBitmap); 
    BOOL bRet = BitBlt(hDC, 0, 0, w, h, hScreen, x1, y1, SRCCOPY); 
    // save bitmap to clipboard 
    OpenClipboard(NULL); 
    EmptyClipboard(); 
    SetClipboardData(CF_BITMAP, hBitmap); 
    CloseClipboard(); 
    // clean up 
    SelectObject(hDC, old_obj); 
    /*DeleteDC(hDC); 
    ReleaseDC(NULL, hScreen); 
    DeleteObject(hBitmap);*/ 
} 

然後,設置hdr.bfType即使在hf != INVALID_HANDLE_VALUE的地方。

變化

if (hf == INVALID_HANDLE_VALUE) 
     //errhandler("CreateFile", hwnd); 
    hdr.bfType = 0x4d42;  // 0x42 = "B" 0x4d = "M" 

if (hf == INVALID_HANDLE_VALUE) 
    { 
     //errhandler("CreateFile", hwnd); 
    } 
    hdr.bfType = 0x4d42;  // 0x42 = "B" 0x4d = "M" 

(加括號)

使用LPCTSTR代替LPTSTR類型的pszFile,這是CreateBMPFile參數也不錯 避免編譯器警告當字符串文字傳遞。

+0

一個不正確的數據類型讓我撓了兩個小時。非常感謝! XD –