首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >hwnd转ppm问题

hwnd转ppm问题
EN

Stack Overflow用户
提问于 2012-08-17 00:31:48
回答 1查看 275关注 0票数 0

我有一个功能,保存一个hwnd到一个ppm文件。此函数的灵感来自于一个msdn示例。msdn示例和我的函数都可以工作,但是...我有个问题。

但首先,下面是函数。

代码语言:javascript
复制
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时间,但我的目标不是将这个图片保存到磁盘。我这样做只是为了调试目的)

提前感谢您的帮助

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-08-17 07:46:18

您的问题是,DIB中的每一行图像数据都必须与DWORD对齐(即在4字节的倍数上对齐)。

代码语言:javascript
复制
dwBmpSize = w*bi.biBitCount*h;

这实际上应该是:

代码语言:javascript
复制
dwBmpSize = ((w*bi.biBitCount+3)&~3) *h;

然后,在编写PPM文件时,您必须考虑到这一点。

此外,图像是颠倒的,因为默认情况下DIB是“自下而上”的(第0行在底部)。要将其设置为“自上而下”,请将biHeight字段设置为负值。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11991675

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档