3

此代码适用于 32、24、16、8、4 bpp 图像。但不是 1 bpp。

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

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")

void GetWindowBitmapBitsAndSave(const HWND& hWnd, int nBitCount, char *szFilePath);
void EnumerateBits(LPBYTE pBits, int nBitCount, int nWidth, int nHeight);

int main(int argc, char **argv)
{   
    //GetWindowBitmapBits(HWND_DESKTOP, 32);
    //32, 24, 16, 8, 4 works fine...
    GetWindowBitmapBitsAndSave(HWND_DESKTOP, 1, "test.bmp");

    return 0;
}

void EnumerateBits(LPBYTE pBits, int nBitCount, int nWidth, int nHeight)
{
    int nPixels = nWidth * nHeight; 
    WORD wByteCount = nBitCount / 8; 
    if(wByteCount == 0)
        wByteCount = 1;
    int nBytes = nPixels * wByteCount; 

    for(int i = 0; i < nBytes; i += wByteCount) 
    { 
        int r = (int)(*(pBits+i));
        //int g = (int)(*(pBits+i+1));
        //int b = (int)(*(pBits+i+2));

        //just for test
        if(r != 0 /*&& g != 0 && b != 0*/)
            if(r != 255 /*&& g != 255 && b != 255*/)
            //printf("(%d, %d, %d)\n", r, g, b);
                    printf("%d\n", r);
    } 
}

void GetWindowBitmapBitsAndSave(const HWND& hWnd, int nBitCount, char* szFilePath)
{
    HWND hScreenWnd = hWnd;
    if(!hScreenWnd)
        hScreenWnd = HWND_DESKTOP;

    //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;
    }

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

    int nWidth = 0;
    int nHeight = 0;

    if(hScreenWnd != HWND_DESKTOP)
    {
        RECT rect;
        GetClientRect(hScreenWnd, &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;
    BITMAPINFOHEADER BitmapInfoHeader;

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

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

    DWORD dwSizeImage = dwBytes * nHeight;
    BitmapInfoHeader.biSizeImage = dwSizeImage;

    BITMAPINFO* bitmapInfo = new BITMAPINFO[sizeof(BITMAPINFO) + sizeof(RGBQUAD) * nColorTableEntries];
    bitmapInfo->bmiHeader = BitmapInfoHeader;

    if(nBitCount < 16)
    {
        for(int i = 0; i != nColorTableEntries; ++i)
        {
            bitmapInfo->bmiColors[i].rgbRed = 
                bitmapInfo->bmiColors[i].rgbGreen =
                bitmapInfo->bmiColors[i].rgbBlue = (BYTE)(i*(255/(nColorTableEntries-1)));
            bitmapInfo->bmiColors[i].rgbReserved = 0;
        }
    }

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

    //save bitmap
    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)
    {
        fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, pFile);
        fwrite(bitmapInfo, nHeaderSize,1,pFile);
        fwrite(lpDibBits, dwSizeImage, 1, pFile);
        fclose(pFile);
    }

    EnumerateBits(lpDibBits, nBitCount, nWidth, nHeight);

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

第一个问题:为什么当位数为1时,除了黑白之外还有颜色?(但图像是单色的。只需在 GetWindowBitmapBitsAndSave 函数中注释 EnumerateBits 调用)。

第二个问题:如何正确计算颜色位数组的偏移量?

4

0 回答 0