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位,则需要计算。

              参考上面第二个例子

             

                                   

                                      

  • 相关阅读:
    warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
    Windows10+CLion+OpenCV4.5.2开发环境搭建
    Android解决部分机型WebView播放视频全屏按钮灰色无法点击、点击全屏白屏无法播放等问题
    MediaCodec.configure Picture Width(1080) or Height(2163) invalid, should N*2
    tesseract
    Caer -- a friendly API wrapper for OpenCV
    Integrating OpenCV python tool into one SKlearn MNIST example for supporting prediction
    Integrating Hub with one sklearn mnist example
    What is WSGI (Web Server Gateway Interface)?
    Hub --- 机器学习燃料(数据)的仓库
  • 原文地址:https://www.cnblogs.com/strive-sun/p/14115809.html
Copyright © 2011-2022 走看看