Как мне исправить альфа-значение после вызова текстовых функций GDI?

У меня есть приложение, использующее эффект стекла Aero, поэтому каждый пиксель имеет альфа-значение в дополнение к значениям красного, зеленого и синего цветов. У меня есть один настраиваемый элемент управления со сплошным белым фоном (альфа = 255). Я хотел бы нарисовать сплошной текст на элементе управления с помощью текстовых функций GDI. Однако эти функции устанавливают для альфа-значения произвольное значение, заставляя текст полупрозрачно отображать любое окно, находящееся под моим приложением.

После вызова рендеринга текста я хотел бы пройтись по всем пикселям в элементе управления и вернуть их альфа-значение на 255. Как лучше всего это сделать?

Мне не повезло с функциями BitBlt, GetPixel и SetPixel. Похоже, они не обращают внимания на значение альфа.

Вот другие решения, которые я рассмотрел и отверг:

  • Нарисуйте растровое изображение, затем скопируйте растровое изображение на устройство: при таком подходе визуализация текста не использует характеристики монитора (например, ClearText). Если вы знаете способ заставить GDI отображать текст в растровое изображение точно так, как он будет отображаться на экране, это также решит мою проблему.
  • Использовать GDI + для рендеринга текста: это приложение изначально использовало GDI + для рендеринга текста (до того, как я начал работать над поддержкой Aero). Я перешел на GDI из-за трудностей, с которыми я столкнулся при попытке точно измерить строки с помощью GDI +. Я бы предпочел не переключаться обратно.
  • Установите область Aero, чтобы избежать рассматриваемого элемента управления: окно моего приложения на самом деле является дочерним окном другого приложения, запущенного в другом процессе. У меня нет прямого контроля над настройками Aero в окне верхнего уровня.

Приложение написано на C # с использованием Windows Forms, хотя я не упоминал выше, как использовать Interop для вызова функций Win32 API.


person Daniel Stutzbach    schedule 22.04.2010    source источник


Ответы (2)


Ниже представлено решение, к которому я пришел. Это некрасиво и, вероятно, можно было бы упростить, но это работает. Идея состоит в том, чтобы создать объект BufferedGraphics на основе исходного объекта Graphics (т. Е. Экрана). В объекте 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, вероятно, необязательно, но как только я заработал, я не стал тестировать все перестановки, чтобы выяснить, какие из них необходимы.

person Daniel Stutzbach    schedule 28.04.2010
comment
Просто примечание о стиле кода: все операторы using () можно писать друг под другом без фигурных скобок, например: using (something) ‹br› using (something) ‹br› using (something) ‹br› {...} - person ygoe; 08.05.2010
comment
Мне просто интересно, проверяли ли вы производительность этой реализации при использовании рендеринга текста GDI +? - person Matthew Layton; 17.09.2013
comment
Кроме того, можно ли изменить это для работы с прозрачным растровым изображением? - Очевидно, буфер, используемый BufferedGraphics, не поддерживает альфа-канал ... какие-нибудь мысли? - person Matthew Layton; 17.09.2013

Вы можете попробовать использовать GDI + на отдельном растровом изображении, скопировав его на экран. Преимущество состоит в том, что альфа-канал текста , нарисованного с помощью GDI + покажет цвет растрового изображения (которое вы бы покрасили в белый цвет) вместо того, чтобы сделать растровое изображение прозрачным.

Но действительно, GDI + имеет очень глючную или просто неточную функцию измерения текста. Но, возможно, вы можете использовать функции GDI для этого. В конце концов, рендеринг текста GDI + должен выглядеть точно так же, как рендеринг текста GDI, который у вас есть сейчас, так что, возможно, стоит попробовать.

person Daniel A.A. Pelsmaeker    schedule 22.04.2010
comment
К сожалению, текстовые функции GDI + из Graphics.DrawString не отображают текст точно так же, как GDI в TextRenderer.DrawText. Текст всегда немного шире и выглядит объемнее. Однако в Windows 7 разница кажется мне меньше, чем в XP (оба с ClearType). - person ygoe; 08.05.2010