c# Bitmap.GetHbitmap() 更改图像的位数

Dav*_*Pyo 5 c# gdi+

我正在使用Bitmap.GetHbitmap将图像从 C# 传递到 C++ dll,如下所示。

Bitmap img = Bitmap.FromFile(PATH);   // this is 24bppRGB bitmap.
IntPtr hBit = img.GetHbitmap();       // Make hbitmap for c++ dll.
Run Code Online (Sandbox Code Playgroud)

这是问题:

Bitmap temp = Bitmap.FromHbitmap(hBit); // It changes to 32bppRGB.
Run Code Online (Sandbox Code Playgroud)

我需要 C++ dll 方法的 24bpp 位图,但GetHbitmap()更改了位计数。

我怎样才能制作24bpp HBITMAP

Ian*_*oyd 2

简洁版本

使用Bitmap.LockBitsCreateDIBSection手动创建您想要的HBITMAP.

长版

Bitmap.GetHBITMAP始终返回 32bppHBITMAP;无论您实际加载的图像是什么格式。这是因为它是图像内部存储的格式。您需要HBITMAP自己手动创建一个。

您可以使用CreateDIBSection创建您自己的 24bpp 位图。该函数返回一个指针,您可以在其中放置原始像素数据。

幸运的是,GDI+ 允许您通过调用LockBits并指定您想要的像素格式(即PixelFormat24bppRGB)来获取任何您想要的格式的像素数据。然后你只需复制像素数据即可。-Stride、 自上而下或自下而上位图可能存在问题。

  1. BITMAPINFO为我们要创建的位图定义 a :

    BITMAPINFO bm;
    bm.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bm.bmiHeader.biWidth = img.Width;
    bm.bmiHeader.biHeight = -img.Height;      // oriented top-down
    bm.bmiHeader.biPlanes = 1;
    bm.bmiHeader.biBitCount = 24;             // 24bpp
    bm.bmiHeader.biCompression = BI_RGB;      // no compression
    bm.bmiHeader.biSizeImage = 0;             // let Windows determine size
    bm.bmiHeader.biXPelsPerMeter = 0;         // Not used by CreateDIBSection
    bm.bmiHeader.biYPelsPerMeter = 0;         // Not used by CreateDIBSection
    
    Run Code Online (Sandbox Code Playgroud)
  2. 根据位图信息创建 DIBSection,并获取放置像素数据的缓冲区

    Pointer dibPixels; //will receive a point where we can stuff our pixel data
    HBITMAP bmp = CreateDIBSection(0, bmInfo, DIB_RGB_COLORS, out dibPixels, 0, 0);
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用Bitmap.LockBits获取指向所需格式的像素数据的指针:

    BitmapData bitmapData = img.LockBits(
          img.Bounds,          //get entire image
          ImageLockModeRead,
          PixelFormat24bppRGB  //we want the pixel data in 24bpp format
          );
    
    Run Code Online (Sandbox Code Playgroud)
  4. 将像素数据从源图像复制到CreateDIBSectinbitmapData返回的像素缓冲区中:

    int stride = bitmapData.Stride;
    int bufferSize = stride * bmData.Height; 
    CopyMemory(bitmapData.Scan0, dibPixels, bufferSize);
    
    Run Code Online (Sandbox Code Playgroud)
  5. 解锁位:

    img.UnlockBits(bitmapData); 
    
    Run Code Online (Sandbox Code Playgroud)

现在您已HBITMAP准备好位图,可以在七年后传递给您的 dll。

奖励阅读