zoukankan      html  css  js  c++  java
  • 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位,则需要计算。

              参考上面第二个例子

             

                                   

                                      

  • 相关阅读:
    基于mAppWidget实现手绘地图--索引&DEMO
    C语言数据结构----栈的定义及实现
    libvirt命令行文档
    清理系统方法
    Linux 经典电子书共享下载
    使用数组实现队列----《数据结构与算法分析---C语言描述》
    清理系统垃圾
    epoll的内部实现 & 百万级别句柄监听 & lt和et模式非常好的解释
    进程、线程、socket套接字-资源大小 & 切换代价
    网络编程学习-面向工资编程
  • 原文地址:https://www.cnblogs.com/strive-sun/p/14115809.html
Copyright © 2011-2022 走看看