旋转 CImage 并保留其 alpha/transparency 通道
Rotating a CImage and preserving its alpha/transparency channel
我有一些现有代码使用具有 alpha 通道的 CImage,我需要旋转它。
我发现了以下将 CImage 转换为 GDI+ 位图然后旋转它的建议,旋转后的结果最终返回到 CImage 中。
Bitmap* gdiPlusBitmap=Bitmap::FromHBITMAP(atlBitmap.Detach());
gdiPlusBitmap->RotateFlip(Rotate90FlipNone);
HBITMAP hbmp;
gdiPlusBitmap->GetHBITMAP(Color::White, &hbmp);
atlBitmap.Attach(hbmp);
显然它无需实际复制位图字节就可以工作,这很好,但问题是如果您从 HBITMAP 创建位图对象,它会丢弃 alpha 通道。
显然要保留 alpha 通道,您必须改为使用构造函数创建位图
Bitmap(
[in] INT width,
[in] INT height,
[in] INT stride,
[in] PixelFormat format,
[in] BYTE *scan0
);
所以我试图将上面的内容改写为使用这个构造函数,但是 CImage 和 Bitmap 之间的交互有点混乱。我想我需要像这样创建位图
Bitmap* gdiPlusBitmap = new Bitmap(
pCImage->GetWidth(),
pCImage->GetHeight(),
pCImage->GetPitch(),
PixelFormat32bppARGB,
(BYTE *)pCImage->GetBits());
nGDIStatus = gdiPlusBitmap->RotateFlip(Rotate90FlipNone);
但我不确定如何让 CImage 接受更改(这样我最终会旋转原始 CImage),或者在哪里删除 Bitmap 对象。
有谁知道保留 alpha 通道的正确方法吗?
理想情况下,我想避免复制位图数据,但这不是强制性的。
您可以使用Gdiplus::Graphics
在CImage
上绘制位图。
请注意,如果图像不支持 alpha 通道,硬编码 PixelFormat32bppARGB
可能会导致问题。我添加了一些基本的错误检查。
CImage image;
if (S_OK != image.Load(L"c:\test\test.png"))
{
AfxMessageBox(L"can't open");
return 0;
}
int bpp = image.GetBPP();
//get pixel format:
HBITMAP hbmp = image.Detach();
Gdiplus::Bitmap* bmpTemp = Gdiplus::Bitmap::FromHBITMAP(hbmp, 0);
Gdiplus::PixelFormat pixel_format = bmpTemp->GetPixelFormat();
if (bpp == 32)
pixel_format = PixelFormat32bppARGB;
image.Attach(hbmp);
//rotate:
Gdiplus::Bitmap bmp(image.GetWidth(), image.GetHeight(), image.GetPitch(), pixel_format, static_cast<BYTE*>(image.GetBits()));
bmp.RotateFlip(Gdiplus::Rotate90FlipNone);
//convert back to image:
image.Destroy();
if (image.Create(bmp.GetWidth(), bmp.GetHeight(), 32, CImage::createAlphaChannel))
{
Gdiplus::Bitmap dst(image.GetWidth(), image.GetHeight(), image.GetPitch(), PixelFormat32bppARGB, static_cast<BYTE*>(image.GetBits()));
Gdiplus::Graphics graphics(&dst);
graphics.DrawImage(&bmp, 0, 0);
}
我有一些现有代码使用具有 alpha 通道的 CImage,我需要旋转它。
我发现了以下将 CImage 转换为 GDI+ 位图然后旋转它的建议,旋转后的结果最终返回到 CImage 中。
Bitmap* gdiPlusBitmap=Bitmap::FromHBITMAP(atlBitmap.Detach());
gdiPlusBitmap->RotateFlip(Rotate90FlipNone);
HBITMAP hbmp;
gdiPlusBitmap->GetHBITMAP(Color::White, &hbmp);
atlBitmap.Attach(hbmp);
显然它无需实际复制位图字节就可以工作,这很好,但问题是如果您从 HBITMAP 创建位图对象,它会丢弃 alpha 通道。
显然要保留 alpha 通道,您必须改为使用构造函数创建位图
Bitmap(
[in] INT width,
[in] INT height,
[in] INT stride,
[in] PixelFormat format,
[in] BYTE *scan0
);
所以我试图将上面的内容改写为使用这个构造函数,但是 CImage 和 Bitmap 之间的交互有点混乱。我想我需要像这样创建位图
Bitmap* gdiPlusBitmap = new Bitmap(
pCImage->GetWidth(),
pCImage->GetHeight(),
pCImage->GetPitch(),
PixelFormat32bppARGB,
(BYTE *)pCImage->GetBits());
nGDIStatus = gdiPlusBitmap->RotateFlip(Rotate90FlipNone);
但我不确定如何让 CImage 接受更改(这样我最终会旋转原始 CImage),或者在哪里删除 Bitmap 对象。
有谁知道保留 alpha 通道的正确方法吗?
理想情况下,我想避免复制位图数据,但这不是强制性的。
您可以使用Gdiplus::Graphics
在CImage
上绘制位图。
请注意,如果图像不支持 alpha 通道,硬编码 PixelFormat32bppARGB
可能会导致问题。我添加了一些基本的错误检查。
CImage image;
if (S_OK != image.Load(L"c:\test\test.png"))
{
AfxMessageBox(L"can't open");
return 0;
}
int bpp = image.GetBPP();
//get pixel format:
HBITMAP hbmp = image.Detach();
Gdiplus::Bitmap* bmpTemp = Gdiplus::Bitmap::FromHBITMAP(hbmp, 0);
Gdiplus::PixelFormat pixel_format = bmpTemp->GetPixelFormat();
if (bpp == 32)
pixel_format = PixelFormat32bppARGB;
image.Attach(hbmp);
//rotate:
Gdiplus::Bitmap bmp(image.GetWidth(), image.GetHeight(), image.GetPitch(), pixel_format, static_cast<BYTE*>(image.GetBits()));
bmp.RotateFlip(Gdiplus::Rotate90FlipNone);
//convert back to image:
image.Destroy();
if (image.Create(bmp.GetWidth(), bmp.GetHeight(), 32, CImage::createAlphaChannel))
{
Gdiplus::Bitmap dst(image.GetWidth(), image.GetHeight(), image.GetPitch(), PixelFormat32bppARGB, static_cast<BYTE*>(image.GetBits()));
Gdiplus::Graphics graphics(&dst);
graphics.DrawImage(&bmp, 0, 0);
}