将MFC Cimage初始化为纯色

时间:2018-09-04 22:51:18

标签: c++ mfc png atl alpha-transparency

我不使用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

2 个答案:

答案 0 :(得分:1)

可以使用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会更快。

答案 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 < xPNGx < yPNG