将 MFC 图像初始化为纯色

initialise an MFC Cimage to a solid colour

本文关键字:纯色 初始化 图像 MFC      更新时间:2023-10-16

我不使用c ++或MFC/ATL等,所以假设我什么都不知道。

整个画面是,我需要接受带有透明层的 PNG,并将其写成具有指定压缩的 JPEG 以传递给另一个系统。

我在这里想知道的是,如何用纯白色初始化目标 CImage 结构?

到目前为止,我已经这样做了(是的,我知道它还有其他风格问题(

void ClipBoardFuncs::savePNGASJPEG(char filePath[256], char errorBuff[256]) {
int sizeOfErrorBuff = 256;
CImage imagePNG;
CImage imageJPG;
int xPNG, yPNG = 0;
imagePNG.Load(filePath);
xPNG = imagePNG.GetWidth();
yPNG = imagePNG.GetHeight();
//Create my target JPG same size and bit depth specifiying that there is no alpha channel (dwflag last param)
imageJPG.Create(xPNG, yPNG, imagePNG.GetBPP(), 0);
//Let there be white....
for (int x = 0; x <= xPNG; x++)
{
for (int y = 0; y <= yPNG; y++)
{
imageJPG.SetPixelRGB(x, y, 255, 255, 255);
}
}
//Copy the image over onto on the white
//BitBlt copies everything....
//imagePNG.BitBlt(imageJPG.GetDC(), 0, 0);
//Draw is more like the C# draw examples I've seen
imagePNG.Draw(imageJPG.GetDC(), 0, 0);
imageJPG.ReleaseDC();
HRESULT hr = NULL;
hr = imageJPG.Save(filePath, Gdiplus::ImageFormatJPEG);
imagePNG.Destroy();
imagePNG.ReleaseGDIPlus();
imageJPG.Destroy();
imageJPG.ReleaseGDIPlus();

LPCTSTR error = _com_error(hr).ErrorMessage();
strncpy_s(errorBuff, sizeOfErrorBuff, _com_error(hr).ErrorMessage(), _TRUNCATE);
} 

可爱的C#人有这样的答案:

将透明PNG转换为具有非黑色背景色的JPG

但我需要 c++ MFC 解决方案用作 DLL 中的导出函数。

通过导出函数,我的意思是与您在 kernel32 中找到的相同架构.dll - 抱歉,我不知道将这种 DLL 与填充 COM 对象的 DLL 区分开来的术语。

谁能建议一种比我这里有的嵌套 x/y for 循环更快的方法来将 imageJPEG 结构初始化为纯白色?

干杯

4GLGuy

初始化可以用RectangleFillRect来完成(为此,FillRect可能是首选 -Rectangle用当前的笔颜色绘制矩形的轮廓,我们可能不想要(。

因此,序列如下所示:

CImage png;
png.Load(pDoc->filename);
CRect rect{ 0, 0, png.GetWidth(), png.GetHeight() };
CImage jpeg;
jpeg.Create(rect.Width(), rect.Height(), png.GetBPP());
auto dc = jpeg.GetDC();
HBRUSH white = CreateSolidBrush(RGB(255, 255, 255));
FillRect(dc, &rect, white);
png.Draw(dc, 0, 0);
jpeg.ReleaseDC();
jpeg.Save(L"Insert File name here", Gdiplus::ImageFormatJPEG);
jpeg.Destroy();
jpeg.ReleaseGDIPlus();
png.ReleaseGDIPlus();

GDI+ 足够"智能",当您对具有 Alpha 通道的图像进行.Draw时,它会考虑该通道,而无需使用TransparentBlt(或类似内容(。

SetTransparentColor不适用于您在这里尝试做的事情。SetTransparentColor适用于没有Alpha 通道("透明层"(的图像。然后,您可以使用它来选择一种颜色,该颜色将被视为透明 - 这当然很有用,但不是您想要的。

您可以改用memset,但仅适用于红色、绿色和蓝色通道都具有相同值(即黑色、白色或某种灰色阴影(的颜色。否则,您可以使用嵌套循环自行完成填充,但在大多数情况下,您可能希望使用FillRect代替(它可能能够使用图形硬件进行加速,其中循环将非常可靠地在 CPU 上运行 - 最坏的情况是,它们的速度大致相同,但在某些情况下FillRect会更快(。

imagePNG.Draw(imageJPG.GetDC(), 0, 0);

每次调用GetDC都必须有一个后续调用ReleaseDC。另请参阅CImage::GetDC文档。

CImage::GetDC提供存储设备上下文的句柄。此句柄可用于使用标准 GDI 函数进行绘制。稍后应用CImage::ReleaseDC清理手柄。

CImage::Draw可能不知道透明颜色是什么。你必须用TransparentBlt来告诉它透明的颜色是什么。例如,要将红色替换为白色:

HDC hdc = imageJPG.GetDC();
CDC dc;
dc.Attach(hdc);
CRect rc(0, 0, xPNG, yPNG);
dc.FillSolidRect(&rc, RGB(255, 255, 255));
dc.Detach();
imagePNG.TransparentBlt(hdc, rc, RGB(255, 0, 0));//replace red with white
imageJPG.ReleaseDC();
...
imageJPG.Save(...);

或者只使用CImage::SetTransparentColor

imagePNG.SetTransparentColor(RGB(255, 0, 0));
imagePNG.Draw(hdc, rc);
for (int x = 0; x <= xPNG; x++){...}

要使用循环执行此操作,请将循环中的条件更改为x < xPNGx < yPNG