【问题标题】:initialise an MFC Cimage to a solid colour将 MFC Cimage 初始化为纯色
【发布时间】:2019-02-09 23:55:36
【问题描述】:

我不使用 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 for 循环更快的方法来将 imageJPEG 结构初始化为纯白色?

干杯

4GLGuy

【问题讨论】:

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


    【解决方案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 会更快)。

    【讨论】:

    • 感谢您的支持 - 当我添加 CBrush 行时,它无法识别,因此我查找了类定义 (docs.microsoft.com/en-gb/cpp/mfc/reference/…) 并包含 afxwin.h。这导致链接器执行我在 theis 线程中找到的操作 - stackoverflow.com/questions/25031009/…,它目前正在抱怨 windows.h 包含在 afxv_w32.h 中 - 正在处理它。
    • 是因为我开始使用控制台应用程序吗?
    • 我改编了这个stackoverflow.com/questions/22479272/…,但它又变黑了——可惜它真的很快。正在努力...
    • @4GLGuy:我已经修改了代码以展示如何在没有 MFC CBrush 的情况下完成这项工作(真的是一个微不足道的改变)。
    • (琐碎 - 这是我可以用来描述我的 MFC 知识水平的一个词) - 感谢您花时间为我做这件事。我一直在研究其他类型的刷子,但没有信心断言一种刷子与另一种基本相同。我会向您展示我一直在使用 char、wchar_t 和 CString 的乐趣和游戏,但它可能只会让您感到沮丧。我的 C++ 傻瓜书(1994 年)本世纪第一次被打开。
    【解决方案2】:
    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 &lt; xPNGx &lt; yPNG

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-06
      • 2011-01-10
      • 2017-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-10
      相关资源
      最近更新 更多