我不使用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#用户有以下答案:
Convert Transparent PNG to JPG with Non-Black Background Color
但是我需要c ++ MFC解决方案用作DLL中的导出函数。
通过导出函数,我的意思是与您在kernel32.dll中找到的架构相同-抱歉,我不知道将这种DLL与填充COM对象的DLL区分的术语。
有人能提出比将嵌套的x / y循环用于此处的循环更快的将imageJPEG结构初始化为纯白色的方法吗?
欢呼
4GLGuy
答案 0 :(得分:1)
可以使用Rectangle
或FillRect
完成初始化(为此,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
会更快。
答案 1 :(得分:0)
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 < xPNG
和x < yPNG
。