C ++ Как получить снимок экрана в памяти с 16-цветным (4-битным) растровым изображением - PullRequest
0 голосов
/ 11 июня 2018

Я пытаюсь получить изображение с 16-цветным растровым изображением.
Я не могу найти решение в интернет-публикации.

Простая реализация здесь.

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

LPBITMAPINFO ConstructBitmapInfo(int nBits, int nX, int nY);
VOID RocketBuffer(LPVOID lpData);

int _tmain(int argc, _TCHAR* argv[])
{
    HWND hDesktop = NULL;
    HDC hCurrenDC = NULL;
    INT nX, nY;
    LPBITMAPINFO lpBmpInfo;
    HBITMAP hBmpScreen;
    LPVOID lpBmpBuffer = NULL;

    if(NULL == (hDesktop = GetDesktopWindow()))
        return GetLastError();

    if (NULL == (hCurrenDC = GetDC(hDesktop)))
        return GetLastError();

    nX = GetSystemMetrics(SM_CXSCREEN);
    nY = GetSystemMetrics(SM_CYSCREEN);

    HDC hOrgMemDC = NULL;
    hOrgMemDC = CreateCompatibleDC(hCurrenDC);
    lpBmpInfo = ConstructBitmapInfo(4, nX, nY);
    hBmpScreen = CreateDIBSection(hCurrenDC, lpBmpInfo, DIB_RGB_COLORS, &lpBmpBuffer, NULL, 0);

    SelectObject(hOrgMemDC, hBmpScreen);

    if(!BitBlt(hOrgMemDC, 0, 0, nX, nY, hCurrenDC, 0, 0, SRCCOPY))
    {
        return GetLastError();
    }

    LPBYTE lpWriteData = new BYTE[lpBmpInfo->bmiHeader.biSizeImage * 2];

    memcpy(lpWriteData, lpBmpBuffer, lpBmpInfo->bmiHeader.biSizeImage);
    RocketBuffer(lpBmpBuffer);

    delete[] lpWriteData;

    return 0;
}

LPBITMAPINFO ConstructBitmapInfo(int nBits, int nX, int nY)
{   
    int color_num = nBits <= 8 ? 1 << nBits : 0;

    int nBISize = sizeof(BITMAPINFOHEADER) + (color_num * sizeof(RGBQUAD));
    BITMAPINFO  *lpbmi = (BITMAPINFO *) new BYTE[nBISize];

    BITMAPINFOHEADER    *lpbmih = &(lpbmi->bmiHeader);
    lpbmih->biSize = sizeof(BITMAPINFOHEADER);
    lpbmih->biWidth = nX;
    lpbmih->biHeight = nY;
    lpbmih->biPlanes = 1;
    lpbmih->biBitCount = nBits;
    lpbmih->biCompression = BI_RGB;
    lpbmih->biXPelsPerMeter = 0;
    lpbmih->biYPelsPerMeter = 0;
    lpbmih->biClrUsed = 0;
    lpbmih->biClrImportant = 0;
    lpbmih->biSizeImage = (((lpbmih->biWidth * lpbmih->biBitCount + 31) & ~31) >> 3) * lpbmih->biHeight;

    if (nBits >= 16)
        return lpbmi;

    HDC hDC = GetDC(NULL);
    HBITMAP hBmp = CreateCompatibleBitmap(hDC, 1, 1); 
    GetDIBits(hDC, hBmp, 0, 0, NULL, lpbmi, DIB_RGB_COLORS);
    ReleaseDC(NULL, hDC);
    DeleteObject(hBmp);

    return lpbmi;
}

VOID RocketBuffer(LPVOID lpData)
{
    // ...
}

Я не могу вывести lpWriteData в виде * .bmp файла.Это не формат BMP.
Поэтому функция RocketBuffer (LPVOID lpData) не сможет правильно выполнять свою функцию.

Проблема в том, как получить снимок экрана в памяти с 16-цветным растровым изображением.

32-битное цветное изображение
32 Bit Color Image

Мне нужно вот такое 4-битное изображение.
4-битное цветное изображение
4 Bit Color Image

1 Ответ

0 голосов
/ 11 июня 2018

16 цветных 4-битных изображений включает в себя таблицу цветов с 16 цветами.Размер таблицы цветов составляет 16 * 4 байта.BITMAPINFO должно быть достаточно большим для приема цветовой палитры через GetDIBits

Приведенный ниже код работает для следующих растровых изображений:

  • 1-разрядные растровые изображения (монохромные) //bpp = 1
  • 4-битные растровые изображения (16 цветов) //bpp = 4
  • 8-битные растровые изображения (256 цветов) //bpp = 8

.

#include <iostream>
#include <fstream>
#include <vector>
#include <windows.h>

int main()
{
    //4-bit bitmap: bpp = 4
    //valid values with this method bpp = 1, 4, 8
    WORD bpp = 4;

    //color table:
    int colorsize = (1 << bpp) * sizeof(RGBQUAD);

    int width = GetSystemMetrics(SM_CXFULLSCREEN);
    int height = GetSystemMetrics(SM_CYFULLSCREEN);

    HDC hdc = GetDC(HWND_DESKTOP);
    HBITMAP hbitmap = CreateCompatibleBitmap(hdc, width, height);
    HDC memdc = CreateCompatibleDC(hdc);
    HGDIOBJ oldbmp = SelectObject(memdc, hbitmap);
    BitBlt(memdc, 0, 0, width, height, hdc, 0, 0, CAPTUREBLT | SRCCOPY);
    SelectObject(memdc, oldbmp);

    //size in bytes for pixel data:
    DWORD size = ((width * bpp + 31) / 32) * 4 * height;

    std::vector<BYTE> bi_memory;
    bi_memory.resize(sizeof(BITMAPINFOHEADER) + colorsize, 0);
    BITMAPINFO* bi = (BITMAPINFO*)&bi_memory[0];
    bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bi->bmiHeader.biWidth = width;
    bi->bmiHeader.biHeight = height;
    bi->bmiHeader.biPlanes = 1;
    bi->bmiHeader.biBitCount = bpp;
    bi->bmiHeader.biCompression = BI_RGB;
    bi->bmiHeader.biClrUsed = 16;

    std::vector<BYTE> pixels(size + colorsize);
    GetDIBits(hdc, hbitmap, 0, height, &pixels[0], bi, DIB_RGB_COLORS);

    std::ofstream fout(TEXT("c:\\test\\_4bit.bmp"), std::ios::binary);
    if(fout)
    {
        //bitmap file header 
        //(54 = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))
        BITMAPFILEHEADER filehdr = { 'MB', 54 + colorsize + size, 0, 0, 54 };
        fout.write((char*)&filehdr, sizeof(BITMAPFILEHEADER));

        //bitmap info header
        fout.write((char*)&bi->bmiHeader, sizeof(BITMAPINFOHEADER));

        //color table
        fout.write((char*)bi->bmiColors, colorsize);

        //pixel data
        fout.write((char*)pixels.data(), pixels.size());
    }

    //cleanup:
    DeleteObject(memdc);
    DeleteObject(hbitmap);
    ReleaseDC(HWND_DESKTOP, hdc);

    return 0;
}
...