2012-08-16 71 views
0

我有一個將hwnd保存爲ppm文件的功能。 此功能受msdn示例啓發。 msdn示例和我的功能都可以工作,但是...我有一個問題...hwnd至ppm問題

但首先,這裏是函數。

int CaptureAnImage(HWND hWnd) 
{ 
    HDC hdcWindow; 
    HDC hdcMemDC = NULL; 
    HBITMAP hbmScreen = NULL; 
    RECT rc; 
    BITMAPINFOHEADER bi; 

    DWORD dwBmpSize; 
    HANDLE hDIB; 
    char *lpbitmap; 
    int w, h; 
    FILE *f; 

    // Retrieve the handle to a display device context for the client 
    // area of the window. 
    hdcWindow = GetDC(hWnd); 

    // Create a compatible DC which is used in a BitBlt from the window DC 
    hdcMemDC = CreateCompatibleDC(hdcWindow); 
    if(!hdcMemDC) { 
     MessageBox(hWnd, "CreateCompatibleDC has failed","Failed", MB_OK); 
     goto done; 
    } 

    // Get the client area for size calculation 
    GetClientRect(hWnd, &rc); 
    w = rc.right - rc.left; 
    h=rc.bottom-rc.top; 

    // Create a compatible bitmap from the Window DC 
    hbmScreen = CreateCompatibleBitmap(hdcWindow, w, h); 
    if(!hbmScreen) { 
     MessageBox(hWnd, "CreateCompatibleBitmap Failed","Failed", MB_OK); 
     goto done; 
    } 

    // Select the compatible bitmap into the compatible memory DC. 
    SelectObject(hdcMemDC,hbmScreen); 

    // Bit block transfer into our compatible memory DC. 
    if(!BitBlt(hdcMemDC, 
       0,0, 
       w, h, 
       hdcWindow, 
       0,0, 
       SRCCOPY)) { 
     MessageBox(hWnd, "BitBlt has failed", "Failed", MB_OK); 
     goto done; 
    } 

    bi.biSize = sizeof(BITMAPINFOHEADER);  
    bi.biWidth = w;  
    bi.biHeight = h; 
    bi.biPlanes = 1;  
    bi.biBitCount = 24;  
    bi.biCompression = BI_RGB;  

    bi.biSizeImage = 0; 
    bi.biXPelsPerMeter = 0;  
    bi.biYPelsPerMeter = 0;  
    bi.biClrUsed = 0;  
    bi.biClrImportant = 0; 

    dwBmpSize = w*bi.biBitCount*h; 

    // 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. 
    hDIB = GlobalAlloc(GHND,dwBmpSize); 
    lpbitmap = (char *)GlobalLock(hDIB);  

    // Gets the "bits" from the bitmap and copies them into a buffer 
    // which is pointed to by lpbitmap. 
    GetDIBits(hdcWindow, hbmScreen, 0, 
     (UINT)h, 
     lpbitmap, 
     (BITMAPINFO *)&bi, DIB_RGB_COLORS); 

    f = fopen("./test.ppm", "wb"); 
    if (!f) { 
     fprintf(stderr, "cannot create ppm file\n"); 
    goto done; 
    } 
    fprintf(f, "P6\n%d %d\n255\n", w, h); 
    fwrite((LPSTR)lpbitmap, dwBmpSize, 1, f); 
    fclose(f); 

    //Unlock and Free the DIB from the heap 
    GlobalUnlock(hDIB);  
    GlobalFree(hDIB); 

    //Clean up 
done: 
    DeleteObject(hbmScreen); 
    DeleteObject(hdcMemDC); 
    ReleaseDC(hWnd,hdcWindow); 

    return 0; 
} 

因此,這裏產生的圖像:

http://imageshack.us/photo/my-images/853/test2ne.jpg/

正如你所看到的,有在寬度尺寸的問題。也許是因爲窗戶的邊界? 如果在代碼中,我將「w = rc.right - rc.left;」進入「w = rc.right - rc.left - 10;」,那會更好。但我不明白,爲什麼我不得不把「-10」和......一些像素缺失對圖片的右邊(也許10個像素?)

http://imageshack.us/photo/my-images/207/test3jq.jpg

最後一個問題: 有沒有什麼辦法可以讓GetDIBits函數把我的字節按倒序排列? 我不想做像素複製的像素,因爲它會花費一些CPU時間。 (好吧,你可能會說因爲我將這個文件保存到磁盤上,所以我不應該擔心cpu時間,但我的目標不是將此圖片保存到磁盤上,我只是爲了調試目的而這樣做)

在此先感謝您的幫助

+0

多數民衆贊成混合C標準庫與基於窗口的代碼一個真正的不好主意... – perilbrain 2012-08-16 16:40:19

+0

這爲什麼這麼糟糕?我習慣於用C語言(而不是C++)編寫代碼,Windows庫可用於C語言。 – ramone 2012-08-16 16:46:59

+0

http://stackoverflow.com/questions/2185944/why-must-stride-in-the-system-drawing-bitmap-constructor-be-a-multiple-of-4 – 2012-08-16 20:41:56

回答

1

你的問題是,在一個DIB圖像數據的每一行必須DWORD對齊(上的4個字節的倍數,即對齊)。

dwBmpSize = w*bi.biBitCount*h; 

這實際上應該是:

dwBmpSize = ((w*bi.biBitCount+3)&~3) *h; 

這樣您就可以寫PPM文件時考慮到這一點。

此外,圖像是倒置的,因爲默認DIB是「自下而上」(第0行在底部)。爲了使其「自上而下」,將biHeight字段設置爲負值。

+0

謝謝你的幫助,那正是我需要什麼,所以謝謝你:) – ramone 2012-08-17 12:16:59