win32

此文章为小结,仅供参考。

第一种情况,从桌面DC获取RGBA的数据。 32位

HDC hdc, hdcTemp;
RECT rect;
BYTE* bitPointer;
int x, y;
int red, green, blue, alpha;

while(true)
{
    hdc = GetDC(HWND_DESKTOP);
    GetWindowRect(hWND_Desktop, &rect);
            int MAX_WIDTH = rect.right;
        int MAX_HEIGHT = rect.bottom;

    hdcTemp = CreateCompatibleDC(hdc);
    BITMAPINFO bitmap;
    bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
    bitmap.bmiHeader.biWidth = MAX_WIDTH;
    bitmap.bmiHeader.biHeight = MAX_HEIGHT;
    bitmap.bmiHeader.biPlanes = 1;
    bitmap.bmiHeader.biBitCount = 32;
    bitmap.bmiHeader.biCompression = BI_RGB;
    bitmap.bmiHeader.biSizeImage = MAX_WIDTH * 4 * MAX_HEIGHT;
    bitmap.bmiHeader.biClrUsed = 0;
    bitmap.bmiHeader.biClrImportant = 0;
    HBITMAP hBitmap2 = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)(&bitPointer), NULL, NULL);
    SelectObject(hdcTemp, hBitmap2);
    BitBlt(hdcTemp, 0, 0, MAX_WIDTH, MAX_HEIGHT, hdc, 0, 0, SRCCOPY);

    for (int i=0; i<(MAX_WIDTH * 4 * MAX_HEIGHT); i+=4)
    {
        red = (int)bitPointer[i];
        green = (int)bitPointer[i+1];
        blue = (int)bitPointer[i+2];
        alpha = (int)bitPointer[i+3];

    }
}

第二种情况,从文件中获取RGB数据,此处为24位

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

using namespace std;

void main()
{
    HBITMAP hbitmap = (HBITMAP)LoadImage(0, L"panda.bmp",
        IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);

    BITMAP bm;
    GetObject(hbitmap, sizeof(bm), &bm);

    //don't continue for hi color bitmaps
    if (bm.bmBitsPixel > 24) return;

    int ncolors = 1 << bm.bmBitsPixel;
    HDC memdc = CreateCompatibleDC(NULL);
    int bmpinfo_size = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * ncolors;
    std::vector<BYTE> buf(bmpinfo_size);
    BITMAPINFO* bmpinfo = (BITMAPINFO*)buf.data();
    bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    if (!GetDIBits(memdc, hbitmap, 0, bm.bmHeight, NULL, bmpinfo, DIB_RGB_COLORS))
    {
        DWORD err = GetLastError();
        //...
    }

    int dibsize = ((bm.bmWidth * bm.bmBitsPixel + 31) / 32) * 4 * bm.bmHeight;
    std::vector<BYTE> dib(dibsize);
    if (!GetDIBits(memdc, hbitmap, 0, (UINT)bm.bmHeight, &dib[0], bmpinfo, DIB_RGB_COLORS))
    {
        DWORD err = GetLastError();
       
    }

    int dibsize1 = bm.bmWidth * 4 * bm.bmHeight; //这适用于32位 的bmp
    //此后将得到的RGB数据写入File中用于对比
    std::ofstream myfile("myoutput.txt");
    for (int i = 0; i < dibsize; i += 3)
    {
        blue = (int)dib[i];
        green = (int)dib[i + 1];
        red = (int)dib[i + 2];
        std::cout << red << " " << green << " " << blue << std::endl;      
        myfile << red << " " << green << " " << blue << endl;
    }
    myfile.close();

//可以借助第四个例子,查看dib是否有效(测试是有效的)
//比如: HBITMAP hbmp = CreateDIBitmap(hdc, &bmih, CBM_INIT, &dib[0], &dbmi, DIB_RGB_COLORS); 图片是镜像的,还需要一些其他处理,可以参考我的另外一篇文章:https://www.cnblogs.com/strive-sun/p/11975384.html // HWND consoleWindow
= GetConsoleWindow(); // HDC hdc = GetDC(consoleWindow); // int k = 0; // for (int i = 0; i < bm.bmHeight; i++) // { // for (int j = 0; j < bm.bmWidth; j++) // { // SetPixel(hdc, j, i, RGB((int)dib[k+2], (int)dib[k + 1], (int)dib[k])); // k++; // } // } getchar(); }

第三种情况, 将32位的RGBA数据写入bmp文件中,此处没有写入文件,而是复制到hdc用于直接查看

#include <windows.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

    MSG msg = { 0 };
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
    wc.lpszClassName = L"createdibsection_example";
    if (!RegisterClass(&wc))
        return 1;

    if (!CreateWindow(wc.lpszClassName,
        L"createdibsection example",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        0, 0, 640, 480, 0, 0, hInstance, NULL))
        return 2;

    while (GetMessage(&msg, NULL, 0, 0) > 0)
        DispatchMessage(&msg);

    return 0;
}

HBITMAP CreateBitmapAndFillPtrToItsData(unsigned char** ptr_data, int wd, int hgt)
{
    HDC hdcScreen = GetDC(NULL);

    BITMAPINFO bmi;
    memset(&bmi, 0, sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = wd;
    bmi.bmiHeader.biHeight = -hgt; // top-down
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;

    auto bmp = CreateDIBSection(hdcScreen, &bmi, DIB_RGB_COLORS, (void**)ptr_data, NULL, NULL);

    ReleaseDC(NULL, hdcScreen);
    return bmp;
}

void CopyInPixelData(unsigned char* ptr_data, int wd, int hgt)
{
    // this is just an example for tutorial purposes ... generate a red circle
    // in a white field ... real code would load from a file, etc.

    int c_x = wd / 2;
    int c_y = hgt / 2;
    int radius = c_x;
    int i = 0;
    for (int y = 0; y < hgt; y++) {
        for (int x = 0; x < wd; x++) {
            if ((x - c_x) * (x - c_x) + (y - c_y) * (y - c_y) <= radius * radius) {
                ptr_data[i++] = 0;
                ptr_data[i++] = 0;
                ptr_data[i++] = 255;
                ptr_data[i++] = 0;
            }
            else {
                ptr_data[i++] = 255;
                ptr_data[i++] = 255;
                ptr_data[i++] = 255;
                ptr_data[i++] = 0;
            }
        }
    }
}

HBITMAP CreateBitmapFromPixelDataExample(int wd, int hgt)
{
    // create a bitmap such that we get a pointer to where its data is stored
    unsigned char* ptr_data;
    auto bitmap = CreateBitmapAndFillPtrToItsData(&ptr_data, wd, hgt);

    // fill in some pixel data...
    CopyInPixelData(ptr_data, wd, hgt);

    return bitmap;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HBITMAP bitmap;

    switch (message)
    {
    case WM_CREATE: {
        bitmap = CreateBitmapFromPixelDataExample(85, 85);
    } break;

    case WM_CLOSE:
        PostQuitMessage(0);
        break;

    case WM_PAINT: {
        RECT r;
        GetClientRect(hWnd, &r);

        auto hdc_bitmap = CreateCompatibleDC(NULL);
        auto hbm_old = (HBITMAP)SelectObject(hdc_bitmap, bitmap);

        PAINTSTRUCT ps;
        auto hdc = BeginPaint(hWnd, &ps);
        // clear bkgd
        FillRect(hdc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
        // paint in the bitmap we generated from pixel data...
        BitBlt(hdc, 10, 10, 85, 85, hdc_bitmap, 0, 0, SRCCOPY);
        EndPaint(hWnd, &ps);

        SelectObject(hdc_bitmap, hbm_old);
        DeleteDC(hdc_bitmap);

    } break;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

第四种情况,将24位的RGB数据写入bmp文件

 // creating input

    unsigned char pixels[160*120*3]; 
    for (int i=0; i<160*120*3; i++)
        pixels[i] = (i%4==1)*255;        // An BGR (not RGB) 160x120 image.

    // at this point we have some input

    BITMAPINFOHEADER bmih;
    bmih.biSize     = sizeof(BITMAPINFOHEADER);
    bmih.biWidth    = 160;
    bmih.biHeight   = -120;
    bmih.biPlanes   = 1;
    bmih.biBitCount = 24;
    bmih.biCompression  = BI_RGB ;
    bmih.biSizeImage    = 0;
    bmih.biXPelsPerMeter    =   10;
    bmih.biYPelsPerMeter    =   10;
    bmih.biClrUsed    =0;
    bmih.biClrImportant =0;

    BITMAPINFO dbmi;
    ZeroMemory(&dbmi, sizeof(dbmi));  
    dbmi.bmiHeader = bmih;
    dbmi.bmiColors->rgbBlue = 0;
    dbmi.bmiColors->rgbGreen = 0;
    dbmi.bmiColors->rgbRed = 0;
    dbmi.bmiColors->rgbReserved = 0;

    HDC hdc = ::GetDC(NULL);

    HBITMAP hbmp = CreateDIBitmap(hdc, &bmih, CBM_INIT, pixels, &dbmi, DIB_RGB_COLORS);
    if (hbmp == NULL) {
        ::MessageBox(NULL, L"Could not load the desired image image", L"Error", MB_OK);
        return;
    }

    ::ReleaseDC(NULL, hdc);

    // a little test if everything is OK
    OpenClipboard(NULL);
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hbmp);
    CloseClipboard();

    // cleanup
    DeleteObject(hbmp);

第五种情况, 使用SetPixel将bmp(24bit)的RGB写到hdc中

#include<iostream>
#include<fstream>
#include <string>
#include<windows.h>
using namespace std;

#pragma pack(1)
struct header
{
    char header[2];
    int32_t filesize;
    int16_t reser;
    int16_t reser1;
    int32_t dataoffset;
};

struct infoheader
{
    int32_t headersize;
    int32_t width;
    int32_t height;
    int16_t plans;
    int16_t bpp;
    int32_t compression;
    int32_t datasize;
    int32_t re;
    int32_t ve;
    int32_t color;
    int32_t importantcolor;
};

struct  PIxel
{
    unsigned char G;
    unsigned char B;
    unsigned char R;
};

int main()
{
    header h;
    infoheader info;
    PIxel* p;
    ifstream file("panda.bmp", ios::binary);
    if (file.is_open())
    {
        cout << "true" << endl;
        file.read((char*)&h, sizeof(h));
        file.read((char*)&info, sizeof(info));
        cout << info.width << " " << info.height << " " << h.filesize << " " << info.bpp << endl;
        int pa = info.width % 4;
        int size = (((24 * info.width + 31) & ~31) / 8)* info.height;
        char* arr = new char[size];
        file.read(arr, size);
        char* temp = arr;
        int sizep = info.height * info.width;
        p = new PIxel[sizep];

        for (int i = info.height - 1; i >= 0; i--)
        {
            for (int j = 0; j < info.width; j++)
            {
                int index = i * (info.width) + j;
                p[index].B = *(temp++);
                p[index].G = *(temp++);
                p[index].R = *(temp++);
            }
            temp += pa;
        }

        HWND consoleWindow = GetConsoleWindow();
        HDC hdc = GetDC(consoleWindow);
 
        for (int i = 0; i < info.height; i++)
        {
            for (int j = 0; j < info.width; j++)
            {
                int index = i * (info.width) + j;
                PIxel m = p[index];
                SetPixel(hdc, j, i, RGB(m.R, m.G, m.B));
            }
        }
        ReleaseDC(consoleWindow, hdc);

    }

    return 0;
}

 学习bmp这部分需要长时间的积累,我虽然看了很多文档以及很多例子。 到现在头脑都没完全理过来,希望这后面的学习中能够慢慢领悟吧。

一些有意思的链接: 从HBITMAP获取字节

                                 如何将像素数组转换为HBITMAP

注意:

  • 获取位图的颜色数据最快的方法不是逐像素获取(GetPixel),而是使用创建一个DIB(使用CreateDIBSectionAPI或类似工具)并在那里复制原始位图,或者首先分别创建原始位图。

          类似地,GetDIBits将获得位图数据的副本。这样使用CreateDIBSection的好处是,我们可以同时使用位图和指向实际数据的指针,而不必在使用位图时同时进行两种转换。 (需要在实践中体会)

          Link: 如何从HBITMAP获取RGBQUAD?

  • 通常我们的位图是24或32位,即每个像素3个字节,如果需要alpha透明通道,则是4个字节(1个字节8位)。数据需要逐行布置,并且必须与DWORD对齐。如果将每个像素设置为32位,则不必担心填充行/对齐方式。如果是24位,则需要计算。

          参考上面第二个例子

         

                               

                                  

原文地址:https://www.cnblogs.com/strive-sun/p/14115809.html