【问题标题】:Anti aliasing in MFCMFC 中的抗锯齿
【发布时间】:2019-03-13 10:49:48
【问题描述】:

我正在尝试在我的 MFC 应用程序中实现抗锯齿,我正在使用this tutorial 中描述的技术。

  • 创建一个与原始位图大小相同的位图(2x、4x、8x)。
  • 在调整大小的位图上绘制(我只使用简单的图形(线、圆等)。
  • 将 StretchBlt 模式设置为半色调。
  • 并使用 StretchBlt 将大小调整为原始大小。

使用这种方式,在调整大小的位图中绘制它可以工作,但我想创建一个更通用的函数来接收已经绘制的位图并返回抗锯齿,我尝试了这个:

static HBITMAP AntiAliasing(HBITMAP hBitmap)
{
    int escala = 4;

    HBITMAP bmp = __copia(hBitmap); //  Copy the bitmap.

    HDC hMemDC = CreateCompatibleDC(NULL);
    HBITMAP bmpAntigo1 = (HBITMAP)::SelectObject(hMemDC, bmp);

    BITMAP bitmap;
    ::GetObject(hBitmap, sizeof(BITMAP), &bitmap);

    //  Create a bitmap (2x, 4x, 8x) the size of the original bitmap.
    HDC hDCDimensionado = ::CreateCompatibleDC(hMemDC);
    HBITMAP bmpDimensionado = ::CreateCompatibleBitmap(hDCDimensionado, 
                                                        bitmap.bmWidth * escala, 
                                                        bitmap.bmHeight * escala);

    HBITMAP hBmpVelho = (HBITMAP)::SelectObject(hDCDimensionado, bmpDimensionado);

    //  I also tried with {BLACKONWHITE, HALFTONE, WHITEONBLACK}
    int oldStretchBltMode2 = ::SetStretchBltMode(hDCDimensionado, COLORONCOLOR);    

    //  Resize the  bitmap to the new size.
    ::StretchBlt(hDCDimensionado,
        0, 0, bitmap.bmWidth * escala, bitmap.bmHeight * escala, 
        hMemDC, 
        0, 0, bitmap.bmWidth, bitmap.bmHeight, 
        SRCCOPY);

    /*
    *   Here the bitmap has lost his colors and became black and white.
    */

    ::SetStretchBltMode(hDCDimensionado, oldStretchBltMode2);

    //  Set StretchBltMode to halfTone so can mimic the anti aliasing effect.
    int oldStretchBltMode = ::SetStretchBltMode(hMemDC, HALFTONE);

    //  resize to the original size.
    ::StretchBlt(hMemDC, 
        0, 0, bitmap.bmWidth, bitmap.bmHeight, 
        hDCDimensionado, 
        0, 0, escala * bitmap.bmWidth, escala * bitmap.bmHeight, 
        SRCCOPY);

    ::SetStretchBltMode(hMemDC, oldStretchBltMode);
    ::SelectObject(hMemDC, bmpAntigo1);
    ::DeleteDC(hMemDC);
    ::SelectObject(hDCDimensionado, hBmpVelho);
    DeleteDC(hDCDimensionado);

    return bmp;
}

但是这个功能不起作用,结果失去了颜色(所有图纸都变黑了)并且没有抗锯齿。

任何帮助将不胜感激!

【问题讨论】:

  • 即使这段代码可以工作,你能得到的“最佳”结果将是原始位图的模糊版本,它丢失了所有细节。你会失望的。谷歌"FXAA" 寻找更好的算法。
  • 本文中介绍的技术通过光栅化图像并以较低的分辨率显示它来工作。您的尝试不会奏效,因为源图像已在显示分辨率下进行了光栅化。膨胀它不会恢复额外的像素信息。它只会放大光栅化错误。

标签: c++ winapi mfc gdi


【解决方案1】:

来自CreateCompatibleBitmap 的文档:

注意:当一个内存设备上下文被创建时,它最初有一个 选择其中的 1×1 单色位图。如果这个存储设备 在 CreateCompatibleBitmap 中使用 context,即创建的位图 是单色位图。要创建彩色位图,请使用之前的 HDC 用于创建内存设备上下文,如下图 代码:

更改代码并为桌面提供hdc,如下所示:

HDC hdc = ::GetDC(0);
HBITMAP bmpDimensionado = ::CreateCompatibleBitmap(hdc, ...)
::ReleaseDC(0, hdc);


这将显示图像,但是此方法不会产生所需的效果,因为它只是将每个像素放大到更大的尺寸并将其缩小回原始像素。没有与相邻像素的混合。

使用其他方法,例如带有高斯模糊效果的 Direct2D,或者使用 GDI+ 代替插值模式:

Gdiplus::GdiplusStartup...

void foo(HDC hdc)
{
    Gdiplus::Bitmap bitmap(L"file.bmp");
    if(bitmap.GetLastStatus() != 0)
        return 0;
    auto w = bitmap.GetWidth();
    auto h = bitmap.GetHeight();

    auto maxw = w * 2;
    auto maxh = h * 2;
    Gdiplus::Bitmap membmp(maxw, maxh);
    Gdiplus::Graphics memgr(&membmp);
    memgr.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBilinear);
    memgr.DrawImage(&bitmap, 0, 0, maxw, maxh);

    Gdiplus::Graphics gr(hdc);
    gr.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBilinear);
    gr.DrawImage(&membmp, 0, 0, w, h);
}


如果目标窗口至少是 Vista,请使用具有模糊效果的 GDI+ 1.1 版。另见How to turn on GDI+ 1.1 in MFC project
#define GDIPVER 0x0110 //add this to precompiled header file

void blur(HDC hdc)
{
    Gdiplus::Graphics graphics(hdc);
    Gdiplus::Bitmap bitmap(L"file.bmp");
    if(bitmap.GetLastStatus() != 0)
        return;

    Gdiplus::Blur blur;
    Gdiplus::BlurParams blur_param;
    blur_param.radius = 3; //change the radius for different result
    blur_param.expandEdge = TRUE;
    blur.SetParameters(&blur_param);
    bitmap.ApplyEffect(&blur, NULL);

    graphics.DrawImage(&bitmap, 0, 0);
}

【讨论】:

  • 感谢您的回答,它帮助我解决了颜色问题!但是抗锯齿仍然不起作用(边缘稍微改变颜色但看起来不像抗锯齿),如果我在调整到原始大小时直接在调整大小的位图上绘制抗锯齿工作。你知道为什么吗?
  • 查看编辑。您可能正在寻找“模糊效果”,而不是“抗锯齿”。您可以使用 Direct2D 或 Gdiplus(1.1 版)应用模糊效果。或者在 Gdi+ 中使用特定的“插值模式”放大/缩小图像
  • 是的,我看到了您的编辑,但仅使用 GDI 是否可行?
  • 没有用于此的 GDI 函数。 StretchBlt 不查看相邻像素。 HALFTONECOLORONCOLOR 仅更改像素与背景的组合方式。
猜你喜欢
  • 2014-02-18
  • 1970-01-01
  • 2016-06-28
  • 2011-07-05
  • 2014-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多