调用 GDI 文本函数后如何修复 alpha 值?

发布于 2024-08-30 08:43:15 字数 743 浏览 7 评论 0原文

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

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

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

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

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

该应用程序是使用 Windows 窗体用 C# 编写的,但我并未使用 Interop 来调用 Win32 API 函数。

I have a application that uses the Aero glass effect, so each pixel has an alpha value in addition to red, green, and blue values. I have one custom-draw control that has a solid white background (alpha = 255). I would like to draw solid text on the control using the GDI text functions. However, these functions set the alpha value to an arbitrary value, causing the text to translucently show whatever window is beneath my application's.

After calling rendering the text, I would like to go through all of the pixels in the control and set their alpha value back to 255. What's the best way to do that?

I haven't had any luck with the BitBlt, GetPixel, and SetPixel functions. They appear to be oblivious to the alpha value.

Here are other solutions that I have considered and rejected:

  • Draw to a bitmap, then copy the bitmap to the device: With this approach, the text rendering does not make use of the characteristics of the monitor (e.g., ClearText). If you know of a way to get GDI to render the text to the bitmap exactly as it would render to the screen, that would also solve my problem.
  • Use GDI+ for text rendering: This application originally used GDI+ for text rendering (before I started working on Aero support). I switched to GDI because of difficulties I encountered trying to accurately measure strings with GDI+. I'd rather not switch back.
  • Set the Aero region to avoid the control in question: My application's window is actually a child window of a different application running in a different process. I don't have direct control over the Aero settings on the top-level window.

The application is written in C# using Windows Forms, though I'm not above using Interop to call Win32 API functions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

饮湿 2024-09-06 08:43:15

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

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 属性可能没有必要,但是一旦我让它工作起来,我就不再费心测试所有排列来找出需要哪些排列(如果有的话)。

Below is the solution I eventually came up with. It's kind of ugly and could probably be simplified, but it works. The idea is to create a BufferedGraphics object based on the original Graphics object (i.e., the screen). In the BufferedGraphics object, TextRenderer.DrawText() will render the text exactly like it would if it was drawing to the screen. I then create a regular graphics object, copy the Buffered Graphics object to the regular graphics object, and finally draw the regular graphics object to the screen.

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);
        }
    }
}

Setting all of the CompositingMode attributes probably isn't necessary, but once I got it working I didn't bother testing all the permutations to figure out which, if any, are needed.

毁我热情 2024-09-06 08:43:15

您可能想尝试在单独的位图上使用 GDI+,并将其复制到屏幕上。优点是 使用 GDI+ 绘制的文本的 alpha< /a> 将显示位图的颜色(您将其涂成白色),而不是使位图透明。

但事实上,GDI+ 的文本测量功能存在很多问题或不准确。但也许您可以使用 GDI 函数为此。最后,您的 GDI+ 文本渲染应该看起来与您现在拥有的 GDI 文本渲染完全相同,因此可能值得一试。

You might want to try using GDI+ on a separate bitmap, copying that to the screen. The advantage is that the alpha of text drawn with GDI+ will show the color of the bitmap (which you would've painted white) instead of making the bitmap transparant.

But indeed, GDI+ has very buggy or just inaccurate text measuring functionality. But maybe you can use the GDI functions for that. In the end, your GDI+ text rendering should look exactly like the GDI text rendering you have now, so it might be worth a try.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文