如何将GDI+的Image*转换为Bitmap*

7

我正在使用C++和GDI+编写代码。

我使用Image的GetThumbnail()方法来获取缩略图。 然而,我需要将其转换为HBITMAP。 我知道以下代码可以获得GetHBITMAP:


```cpp HBITMAP hBitmap; thumbnail->GetHBITMAP(Color::White, &hBitmap); ```
Bitmap* img;
HBITMAP temp;
Color color;
img->GetHBITMAP(color, &temp); // if img is Bitmap*  this works well。

但是我该如何快速将Image*转换为Bitmap*呢?非常感谢!
实际上,现在我必须使用以下方法:
int width = sourceImg->GetWidth(); // sourceImg is Image*
int height = sourceImg->GetHeight();
Bitmap* result = new Bitmap(width, height,PixelFormat32bppRGB);
Graphics gr(result);
//gr.SetInterpolationMode(InterpolationModeHighQuality);
gr.DrawImage(sourceImg, 0, 0, width, height);

我真的不知道为什么他们不提供Image* -> Bitmap*方法,而是让GetThumbnail() API返回一个Image对象....


5
你的操作方式是正确的。一般而言,无法“快速”转换的原因是 Image 并不一定是位图 - 它可以是矢量图像(尽管我知道的唯一被 GDI+ 支持的矢量格式是 WMF/EMF)。我想,在这种情况下,GetThumbnail 也会生成一个矢量图像。 - Pavel Minaev
3个回答

3
Image* img = ???;
Bitmap* bitmap = new Bitmap(img);

编辑: 我正在查看GDI+的.NET参考文献,但这是.NET实现该构造函数的方式。

using (Graphics graphics = null)
{
    graphics = Graphics.FromImage(bitmap);
    graphics.Clear(Color.Transparent);
    graphics.DrawImage(img, 0, 0, width, height);
}

所有这些功能都在 GDI+ 的 C++ 版本中可用。

2
我没有看到任何接受Image*Bitmap构造函数。 - Rob Kennedy
1
我也是~~ 在.NET中可能可以,但C++不提供这个构造函数。 - user25749

3

首先你可以尝试使用dynamic_cast,因为在许多情况下(如果不是大多数情况- 至少是在我的用例中),Image 是由Bitmap实现的。所以

Image* img = getThumbnail( /* ... */ );
Bitmap* bitmap = dynamic_cast<Bitmap*>(img);
if(!bitmap)
    // getThumbnail returned an Image which is not a Bitmap. Convert.
else
    // getThumbnail returned a Bitmap so just deal with it.

然而,如果某种方式不行(bitmap 将会是 nullptr),那么您可以尝试更通用的解决方案。例如,使用 Save 方法将 Image 保存到一个 COM IStream 中,然后再使用 Bitmap::FromStream 从该流中创建 Bitmap。可以使用 CreateStreamOnHGlobal WinAPI 函数创建一个简单的 COM IStream。但是这不是高效的,特别是对于较大的流来说。测试时可以这样做。还有其他类似的解决方案,可以从阅读 ImageBitmap 文档中推导出来。遗憾的是我自己没有尝试过(使用不是 BitmapImage),所以我不是完全确定。

1
实际上,问题中的代码是从通用图像中获取位图的完美方法。 - Pavel Minaev
1
我的答案提供了潜在的最优解,因为 dynamic_cast 的成本很小(与绘制/复制图像相比),并且在大多数情况下我认为它会成功。如果不成功,那么我的版本或问题中的代码(在我的答案之后添加)是一种方法。问题中的代码似乎更简单、更安全。但是我不确定它如何处理透明度。此外,如果可能的话,重构 getThumbnail 以返回 Bitmap* 可能会很有用,因为它似乎不太可能生成矢量图形。 - Adam Badura
我同意对于一个位图图像,GetThumbnail() 方法应该返回指向实际的 Bitmap 对象的 Image*。 但是在尝试后,我发现它指向了 Image 对象... - user25749

2
据我所知,您只需要创建一个位图并将图像绘制到其中:
Bitmap* GdiplusImageToBitmap(Image* img, Color bkgd = Color::Transparent)
{
    Bitmap* bmp = nullptr;
    try {
        int wd = img->GetWidth();
        int hgt = img->GetHeight();
        auto format = img->GetPixelFormat();
        Bitmap* bmp = new Bitmap(wd, hgt, format);
        auto g = std::unique_ptr<Graphics>(Graphics::FromImage(bmp));
        g->Clear(bkgd);
        g->DrawImage(img, 0, 0, wd, hgt);
    } catch(...) {
        // this might happen if img->GetPixelFormat() is something exotic
        // ... not sure
    }
    return bmp;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接