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 呼び出しをコメントするだけです)。

2 番目の質問: カラー ビット配列のオフセットを正しく計算するにはどうすればよいですか?

4

0 に答える 0