首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >C++如何在内存中获取16色(4位)位图的屏幕截图输出

C++如何在内存中获取16色(4位)位图的屏幕截图输出
EN

Stack Overflow用户
提问于 2018-06-11 17:06:15
回答 1查看 352关注 0票数 1

我正在尝试获得一张16色位图的图像。

我在网上发帖找不到解决方案。

这里的实现很简单。

代码语言:javascript
复制
#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位彩色图像

我想像这样的4位图像。

4位彩色图像

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-06-12 00:09:56

16色4位图像包括具有16种颜色的颜色表。颜色表大小为16 *4字节。通过GetDIBits接收调色板时,BITMAPINFO应足够大

下面的代码适用于以下位图:

  • 1位位图(单色) //bpp = 1

  • 4位位图(16色) //bpp = 4

  • 8位位图(256色) //bpp = 8

代码语言:javascript
复制
#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;
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50794015

复制
相关文章

相似问题

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