将MFC Cimage初始化为纯色

问题描述 投票:2回答:2

我不使用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对象的术语。

任何人都可以建议一种更快的方法来将imageJPEG结构初始化为纯白色,而不是嵌套的x / y for循环吗?

干杯

4GLGuy

c++ mfc png atl alpha-transparency
2个回答
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会更快。


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

© www.soinside.com 2019 - 2024. All rights reserved.