【问题标题】:How do I fix the alpha value after calling GDI text functions?调用 GDI 文本函数后如何修复 alpha 值?
【发布时间】:2011-02-11 02:27:57
【问题描述】:

我有一个使用 Aero 玻璃效果的应用程序,因此除了红色、绿色和蓝色值之外,每个像素都有一个 alpha 值。我有一个具有纯白色背景(alpha = 255)的自定义绘制控件。我想使用 GDI 文本函数在控件上绘制纯文本。但是,这些函数将 alpha 值设置为任意值,导致文本半透明地显示我的应用程序下方的任何窗口。

调用渲染文本后,我想遍历控件中的所有像素并将它们的 alpha 值设置回 255。最好的方法是什么?

BitBltGetPixelSetPixel 函数我没有任何运气。他们似乎没有注意到 alpha 值。

以下是我考虑过但拒绝的其他解决方案:

  • 绘制到位图,然后将位图复制到设备:使用这种方法,文本渲染不会利用监视器的特性(例如 ClearText)。如果您知道一种让 GDI 将文本渲染到位图的方法完全就像它会渲染到屏幕上一样,那也可以解决我的问题。
  • 使用 GDI+ 进行文本渲染:此应用程序最初使用 GDI+ 进行文本渲染(在我开始从事 Aero 支持工作之前)。由于在尝试使用 GDI+ 准确测量字符串时遇到困难,我转而使用 GDI。我宁愿不转回去。
  • 设置 Aero 区域以避免有问题的控件:我的应用程序窗口实际上是在不同进程中运行的不同应用程序的子窗口。我无法直接控制顶级窗口中的 Aero 设置。

该应用程序是使用 Windows 窗体用 C# 编写的,尽管我没有使用 Interop 调用 Win32 API 函数。

【问题讨论】:

    标签: c# .net winforms gdi aero


    【解决方案1】:

    您可能想尝试在单独的位图上使用 GDI+,然后将其复制到屏幕上。优点是text drawn with GDI+ 的 alpha 将显示位图的颜色(您将其涂成白色)而不是使位图透明。

    但实际上,GDI+ 有很多错误或者只是不准确的文本测量功能。但也许您可以为此使用GDI functions。最后,您的 GDI+ 文本渲染应该看起来与您现在的 GDI 文本渲染完全一样,因此值得一试。

    【讨论】:

    • 不幸的是,Graphics.DrawString 中的 GDI+ 文本函数不能像 TextRenderer.DrawText 中的 GDI 一样呈现文本。文字总是有点宽,看起来更宽敞。然而,在 Windows 7 中,对我来说差异看起来比在 XP 上要小(两者都使用 ClearType)。
    【解决方案2】:

    以下是我最终想出的解决方案。这有点难看,可能会被简化,但它确实有效。这个想法是基于原始 Graphics 对象(即屏幕)创建一个 BufferedGraphics 对象。在 BufferedGraphics 对象中,TextRenderer.DrawText() 将呈现文本,就像它在屏幕上绘制时一样。然后我创建一个常规图形对象,将Buffered Graphics对象复制到常规图形对象中,最后将常规图形对象绘制到屏幕上。

    Rectangle inner = new Rectangle(Point.Empty, ContentRectangle.Size);
    using (BufferedGraphics bg = BufferedGraphicsManager.Current.Allocate(e.Graphics, inner)) {
        using (Bitmap bmp = new Bitmap(inner.Width, inner.Height, bg.Graphics)) {
            using (Graphics bmpg = Graphics.FromImage(bmp)) {
                bg.Graphics.Clear(BackColor);
                do_my_drawing(bg.Graphics);
                bg.Graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
                e.Graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
                bmpg.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
    
                bg.Render(bmpg);
                e.Graphics.DrawImageUnscaledAndClipped(bmp, ContentRectangle);
            }
        }
    }
    

    可能没有必要设置所有 CompositingMode 属性,但一旦我开始使用它,我就不会费心测试所有排列来确定需要哪些排列(如果有的话)。

    【讨论】:

    • 只是代码风格的一个注释:你可以在没有大括号的情况下将所有 using() 语句写在彼此下,即: using (something)
      using (something)
      using (something)
      { ... }
    • 我只是想知道,您是否针对使用 GDI+ 文本渲染测试了此实现的性能?
    • 另外,可以修改它以使用透明位图吗? - 显然 BufferedGraphics 使用的缓冲区不支持 alpha 通道...有什么想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 2020-12-01
    • 2019-09-24
    相关资源
    最近更新 更多