使用Image.FromHbitmap时丢失Alpha信息的解决方案

本文介绍了一种从HBITMAP转换为GDI+ Bitmap的方法,并确保保留Alpha通道信息。通过详细步骤和代码示例展示了如何利用GetDIBits函数获取位图数据,再创建新的GDI+ Bitmap并复制像素数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用Image.FromHbitmap创建Image时,会丢失Alpha信息(或者说GDI+在使用HBITMAP创建Bitmap时都不会携带Alpha信息)。可以使用下面代码来解决:

Bitmap* CreateBitmapFromHBITMAP(IN HBITMAP hBitmap)
{
    BITMAP bmp = { 0 };
    if ( 0 == GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bmp) )
    {
        return FALSE;
    }
     
    // Although we can get bitmap data address by bmp.bmBits member of BITMAP 
    // which is got by GetObject function sometime,
    // we can determine the bitmap data in the HBITMAP is arranged bottom-up 
    // or top-down, so we should always use GetDIBits to get bitmap data.
    BYTE *piexlsSrc = NULL;
    LONG cbSize = bmp.bmWidthBytes * bmp.bmHeight;
    piexlsSrc = new BYTE[cbSize];
     
    BITMAPINFO bmpInfo = { 0 };
    // We should initialize the first six members of BITMAPINFOHEADER structure.
    // A bottom-up DIB is specified by setting the height to a positive number, 
    // while a top-down DIB is specified by setting the height to a negative number.
    bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmpInfo.bmiHeader.biWidth = bmp.bmWidth;
    bmpInfo.bmiHeader.biHeight = bmp.bmHeight; // 正数,说明数据从下到上,如未负数,则从上到下
    bmpInfo.bmiHeader.biPlanes = bmp.bmPlanes;
    bmpInfo.bmiHeader.biBitCount = bmp.bmBitsPixel;
    bmpInfo.bmiHeader.biCompression = BI_RGB;
     
    HDC hdcScreen = CreateDC(L"DISPLAY", NULL, NULL,NULL);
    LONG cbCopied = GetDIBits(hdcScreen, hBitmap, 0, bmp.bmHeight, 
                        piexlsSrc, &bmpInfo, DIB_RGB_COLORS);
    DeleteDC(hdcScreen);
    if ( 0 == cbCopied )
    {
        delete [] piexlsSrc;
        return FALSE;
    }
     
    // Create an GDI+ Bitmap has the same dimensions with hbitmap
    Bitmap *pBitmap = new Bitmap(bmp.bmWidth, bmp.bmHeight, PixelFormat32bppPARGB);
     
    // Access to the Gdiplus::Bitmap's pixel data
    BitmapData bitmapData;
    Rect rect(0, 0, bmp.bmWidth, bmp.bmHeight);
    if ( Ok != pBitmap->LockBits(&rect, ImageLockModeRead, 
            PixelFormat32bppPARGB, &bitmapData) )
    {
        SAFE_DELETE(pBitmap);
        return NULL;
    }
     
    BYTE *pixelsDest = (BYTE*)bitmapData.Scan0;
    int nLinesize = bmp.bmWidth * sizeof(UINT);
    int nHeight = bmp.bmHeight;
     
    // Copy pixel data from HBITMAP by bottom-up.
    for ( int y = 0; y < nHeight; y++ )
    {
        // 从下到上复制数据,因为前面设置高度时是正数。
        memcpy_s( 
             (pixelsDest + y * nLinesize), 
             nLinesize, 
             (piexlsSrc + (nHeight - y - 1) * nLinesize), 
             nLinesize);
    }
     
    // Copy the data in temporary buffer to pBitmap
    if ( Ok != pBitmap->UnlockBits(&bitmapData) )
    {
        delete pBitmap;
    }
     
    delete [] piexlsSrc;
    return pBitmap;
}


参考文献:

1.http://stackoverflow.com/questions/335273/how-to-create-a-gdiplusbitmap-from-an-hbitmap-retaining-the-alpha-channel-inf

2.http://blog.youkuaiyun.com/leehong2005/article/details/8607581

3.http://www.cnblogs.com/yedaoq/p/3579036.html

4.http://www.cnblogs.com/yedaoq/p/3587913.html

5.http://stackoverflow.com/questions/9275738/convert-hbitmap-to-bitmap-preserving-alpha-channel

6.http://stackoverflow.com/questions/4627376/use-native-hbitmap-in-c-sharp-while-preserving-alpha-channel-transparency



<think>嗯,用户提供的这段C#代码是关于生成二维码的,但用户的问题是为什么这段代码不能查询字符串数据。首先,我需要仔细阅读代码,理解它的功能,然后找出为什么无法查询字符串数据的原因。 首先,代码的大致流程是创建一个QRCodeGenerator实例,生成QRCodeData,然后创建QRCode对象,生成位图,最后将图片显示在picQRCode控件上。看起来这段代码的主要功能是生成二维码并将其显示出来,而不是查询或处理字符串数据。因此,用户提到的“不能查询字符串数据”可能与代码本身的功能无关。 接下来,我需要分析可能的误解。用户可能认为这段代码应该能够从二维码中读取字符串数据,也就是解码二维码,但实际上代码是用于生成二维码的。生成和解码是两个不同的过程,所以如果用户想要查询字符串数据,可能需要使用解码库,比如ZXing.Net,而不是生成二维码的代码。 另外,代码中存在一些可能的问题。例如,两次设置picQRCode.Image属性,先赋值为img,然后又赋值为qrCodeImage,这可能是不必要的,甚至可能导致资源泄漏。此外,使用Image.FromHbitmap和GetHbitmap可能会引起GDI对象未释放的问题,需要确保正确释放资源。 用户可能的错误在于混淆了生成和解码的功能,或者在使用这段代码,期望它能够读取二维码中的字符串,但实际没有解码步骤。因此,需要指出代码的功能是生成而非读取,并提供解码的方法建议。 最后,总结问题原因,并给出解决方案:用户需要的是解码二维码而非生成,因此应使用相应的解码库和代码来实现查询字符串数据的功能。</think>这段代码是二维码生成代码,无法查询字符串数据的原因及技术分析如下: 一、功能定位错误 1. 该代码的核心功能是生成二维码(QRCodeGenerator),而不是解析二维码 2. 代码流程: - `CreateQrCode(txtText)`:将输入的字符串编码为二维码 - `GetGraphic()`:生成位图图像 - 最终将图片显示在`picQRCode`控件中 二、查询字符串数据需要反向操作 若需要从二维码获取字符串数据,需要: 1. 使用二维码解码库(如ZXing.Net) 2. 典型解码代码结构: ```csharp // 需要添加ZXing.Net引用 var reader = new BarcodeReader(); var result = reader.Decode((Bitmap)picQRCode.Image); string decodedString = result?.Text; ``` 三、原代码潜在问题 1. 重复赋值问题: ```csharp picQRCode.Image = img; // 第一次赋值 picQRCode.Image = qrCodeImage; // 覆盖前值 ``` 会导致GDI对象泄漏,应使用`using`语句: ```csharp using (Bitmap qrCodeImage = qrCode.GetGraphic(20)) { picQRCode.Image = qrCodeImage.Clone() as Image; } ``` 四、解决方案建议 1. 生成与解码分离: ```mermaid graph LR A[生成二维码] --> B[保存/显示图片] C[读取图片] --> D[解码二维码] ``` 2. 若需要完整解决方案,需要: - 生成端:当前代码 - 解析端:添加ZXing.Net等解码库的解析逻辑 五、性能优化提示 使用`System.Drawing.Common`应注意: 1.释放GDI对象 2. 推荐使用`using`语句管理Bitmap资源 3. 大尺寸二维码建议异步生成 总结:该代码本质是二维码生成器,要实现字符串数据查询需要反向的解码流程,二者需要配合使用才能完成完整的"生成-解析"闭环。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值