Поделиться через


Отрисовка текста с помощью Direct2D и DirectWrite

В отличие от других API, таких как GDI, GDI+ или WPF, Direct2D взаимодействует с другим API , DirectWrite, для управления и отрисовки текста. В этом разделе описываются преимущества и взаимодействие этих отдельных компонентов.

Эта тема описана в следующих разделах.

Direct2D обеспечивает добавочное внедрение

Перемещение приложения из одного графического API в другой может быть сложным или не тем, что вы хотите по различным причинам. Это может быть связано с тем, что вам придется поддерживать подключаемые модули, которые по-прежнему принимают старые интерфейсы, так как само приложение слишком велико для переноса на новый API в одном выпуске или потому, что некоторые части нового API желательно, но старый API работает достаточно хорошо для других частей приложения.

Так как Direct2D и DirectWrite реализованы в виде отдельных компонентов, вы можете обновить всю 2D-графическую систему или только текстовую часть. Например, можно обновить приложение для использования DirectWrite для текста, но по-прежнему использовать GDI или GDI + для отрисовки.

Службы текста и отрисовка текста

По мере развития приложений требования к обработке текста становятся все более сложными. Во-первых, текст обычно был ограничен статически выложенным пользовательским интерфейсом, и текст был отрисован в четко определенном поле, например кнопку. Поскольку приложения стали доступны в растущем количестве языков, этот подход стал более сложным, поскольку ширина и высота переведенного текста могут значительно отличаться между языками. Чтобы адаптироваться, приложения начали динамически выкладывать свой пользовательский интерфейс, чтобы зависеть от фактического отрисованного размера текста, а не наоборот.

Чтобы помочь приложениям выполнить эту задачу, DirectWrite предоставляет интерфейс IDWriteTextLayout. Этот API позволяет приложению указать фрагмент текста со сложными характеристиками, такими как различные шрифты и размеры шрифтов, подчеркивания, зачеркиваемые фрагменты, двунаправленный текст, эффекты, многоточие и даже внедренные символы без глифа (например, растровое изображение или значок). Затем приложение может изменить различные характеристики текста, так как он итеративно определяет его макет пользовательского интерфейса. Пример DirectWrite Hello World, показанный на следующем рисунке и в руководстве по началу работы с DirectWrite , показывает многие из этих эффектов.

Снимок экрана примера

Макет может размещать глифы в идеале на основе их ширины (как это делает WPF), или он может привязать глифы к ближайшим позициям пикселей (как делает GDI ).

Помимо получения текстовых измерений, приложение может ударить по различным частям текста. Например, может потребоваться знать, что гиперссылка в тексте щелкается. (Дополнительные сведения о тестировании попаданий см. в разделеКак выполнить тестирование попаданий в разделе макета текста.)

Интерфейс макета текста отделен от API отрисовки, который использует приложение, как показано на следующей схеме:

схема текстового макета и графического API.

Это разделение возможно, так как DirectWrite предоставляет интерфейс отрисовки (IDWriteTextRenderer), который приложения могут реализовать для отрисовки текста с помощью любого нужного графического API. Приложение реализует метод обратного вызова IDWriteTextRenderer::D rawGlyphRun при отрисовке текстового макета. Этот метод несет ответственность за выполнение операций рисования или передачу их вместе.

Для рисования глифов Direct2D предоставляет id2D1RenderTarget::D rawGlyphRun для рисования на поверхность Direct2D и DirectWrite предоставляет IDWriteBitmapRenderTarget::D rawGlyphRun для рисования в область GDI, которую затем можно передать в окно с помощью GDI. Удобно, что DrawGlyphRun в Direct2D и DirectWrite имеют точно совместимые параметры с методом DrawGlyphRun, который приложение реализует в IDWriteTextRenderer.

После аналогичного разделения функции, относящиеся к тексту (например, перечисление шрифтов и управление, анализ глифов и т. д.), обрабатываются DirectWrite вместо Direct2D. Объекты DirectWrite принимаются непосредственно Direct2D. Чтобы помочь существующим приложениям GDI воспользоваться преимуществами DirectWrite, он предоставляет интерфейс метода IDWriteGdiInterop с методами для выполнения следующих действий:

Глифы и текст

Текст представляет собой набор кодовых точек Юникода (символов), с различными стилистическими модификаторами (шрифтами, весами, подчеркиваниями, начерками и т. д.), которые размещаются в прямоугольнике. Глиф, напротив, представляет собой определенный индекс в определенный файл шрифта. Глиф определяет набор кривых, которые могут быть отрисованы, но не имеет никакого текстового значения. Возможно, существует сопоставление "многие ко многим" между глифами и символами. Последовательность глифов, поступающих из того же лица шрифта и которые последовательно выложены на базовом уровне, называется GlyphRun. Как DirectWrite, так и Direct2D вызывают их наиболее точные глифы API отрисовки DrawGlyphRun, и они имеют очень похожие сигнатуры. Ниже приведено имя ID2D1RenderTarget в Direct2D:

STDMETHOD_(void, DrawGlyphRun)(
        D2D1_POINT_2F baselineOrigin,
        __in CONST DWRITE_GLYPH_RUN *glyphRun,
        __in ID2D1Brush *foregroundBrush,
        DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL 
        ) PURE;

И этот метод получен из IDWriteBitmapRenderTarget в DirectWrite:

STDMETHOD(DrawGlyphRun)(
        FLOAT baselineOriginX,
        FLOAT baselineOriginY,
        DWRITE_MEASURING_MODE measuringMode,
        __in DWRITE_GLYPH_RUN const* glyphRun,
        IDWriteRenderingParams* renderingParams,
        COLORREF textColor,
        __out_opt RECT* blackBoxRect = NULL
        ) PURE;

Версия DirectWrite сохраняет базовый источник, режим измерения и параметры выполнения глифа и включает дополнительные параметры.

DirectWrite также позволяет использовать пользовательский отрисовщик для глифов, реализуя интерфейс IDWriteTextRenderer. Этот интерфейс также имеет метод DrawGlyphRun , как показано в следующем примере кода.

STDMETHOD(DrawGlyphRun)(
        __maybenull void* clientDrawingContext,
        FLOAT baselineOriginX,
        FLOAT baselineOriginY,
        DWRITE_MEASURING_MODE measuringMode,
        __in DWRITE_GLYPH_RUN const* glyphRun,
        __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
        __maybenull IUnknown* clientDrawingEffect
        ) PURE;

Эта версия включает дополнительные параметры, которые полезны при реализации пользовательского отрисовщика текста. Окончательный параметр используется для пользовательских эффектов рисования, реализованных приложением. (Дополнительные сведения о эффектах рисования клиента см. в разделе Добавление эффектов рисования клиента в текстовый макет.

Каждый глиф запускается в источнике и помещается в строку, начиная с этого источника. Глифы изменяются текущим преобразованием мира и параметрами отрисовки выделенного текста в связанном целевом объекте отрисовки. Этот API обычно вызывается непосредственно приложениями, выполняющими собственный макет (например, обработчик Word) или приложением, реализующим интерфейс IDWriteTextRenderer .

DirectWrite и Direct2D

Direct2D предоставляет службы отрисовки уровня глифа с помощью DrawGlyphRun. Однако для этого требуется, чтобы приложение реализовало детали отрисовки, которое в основном воспроизводит функциональные возможности API DrawText из GDI самостоятельно.

Поэтому Direct2D предоставляет API,которые принимают текст вместо глифов: ID2D1RenderTarget::D rawTextLayout и ID2D1RenderTarget::D rawText. Оба метода отображаются в поверхности Direct2D. Для отрисовки в поверхность GDI предоставляется IDWriteBitmapRenderTarget::D rawGlyphRun. Но этот метод требует, чтобы настраиваемый отрисовщик текста был реализован приложением. (Дополнительные сведения см. в разделе Отрисовка в раздел GDI Surface .)

Использование текста приложение обычно начинается просто: поместите ОК или Отмену на кнопку фиксированного макета, например. Однако с течением времени она становится более сложной, так как добавляются интернационализация и другие функции. В конечном итоге многим приложениям придется использовать объекты текстового макета DirectWrite и реализовать отрисовщик текста.

Таким образом, Direct2D предоставляет многоуровневые API, которые позволяют приложению запускать просто и увеличивать более сложные возможности, не требуя обратного отслеживания или отказа от рабочего кода. Упрощенное представление показано на следующей схеме:

схема приложений directwrite и direct2d.

DrawText

DrawText — это самый простой интерфейс API для использования. Он принимает строку Юникода, кисть переднего плана, один объект формата и прямоугольник назначения. Он выложит и отрисовывает всю строку в прямоугольнике макета и при необходимости закрепит ее. Это полезно, если вы помещаете простой фрагмент текста в часть пользовательского интерфейса фиксированного макета.

DrawTextLayout

Создав объект IDWriteTextLayout , приложение может начать измерять и упорядочивать текст и другие элементы пользовательского интерфейса, а также поддерживать несколько шрифтов, стилей, подчеркивания и зачеркивание. Direct2D предоставляет API DrawTextLayout , который напрямую принимает этот объект и отрисовывает текст в заданной точке. (Ширина и высота предоставляются объектом макета. Помимо реализации всех ожидаемых функций макета текста, Direct2D интерпретирует любой объект эффекта как кисть и применяет ее к выбранному диапазону глифов. Он также вызывает все встроенные объекты. После этого приложение может вставить символы без глифов (значки) в текст, если это нужно. Еще одним преимуществом использования объекта текстового макета является то, что позиции глифа кэшируются в нем. Таким образом, большое повышение производительности возможно путем повторного использования одного объекта макета для нескольких вызовов рисования и предотвращения пересчета позиций глифов для каждого вызова. Эта возможность отсутствует для объекта DrawText GDI.

DrawGlyphRun

Наконец, приложение может реализовать сам интерфейс IDWriteTextRenderer и вызвать DrawGlyphRun и FillRectangle или любой другой API отрисовки. Все существующее взаимодействие с объектом "Макет текста" останется неизменным.

Пример реализации пользовательского отрисовщика текста см. в разделе "Отрисовка с помощью пользовательского отрисовщика текста".

Отрисовка глифа

Добавление DirectWrite в существующее приложение GDI позволяет приложению использовать API IDWriteBitmapRenderTarget для отрисовки глифов. Метод IDWriteBitmapRenderTarget::D rawGlyphRun, предоставляемый DirectWrite, будет отображаться в сплошном цвете в контроллер памяти, не требуя дополнительных API, таких как Direct2D.

Это позволяет приложению получать расширенные функции отрисовки текста, такие как:

  • Вложенный пиксель ClearType позволяет приложению помещать глифы на под пиксельные позиции, чтобы обеспечить отображение резкого глифа и макет глифа.
  • Защита от Y позволяет более гладкой отрисовке кривых на больших глифах.

Приложение, перемещающееся в Direct2D , также получит следующие функции:

  • Аппаратное ускорение.
  • Возможность заливки текста произвольными кистью Direct2D , такими как радиальные градиенты, линейные градиенты и растровые изображения.
  • Дополнительная поддержка слоев и вырезки через API PushAxisAlignedClip, PushLayer и CreateCompatibleRenderTarget.
  • Возможность поддержки отрисовки текста в сером масштабе. Это правильно заполняет целевой альфа-канал в соответствии с непрозрачностью текстовой кисти и антиализамированием текста.

Для эффективной поддержки аппаратного ускорения Direct2D использует немного другое приближение к гамма-коррекции, называемой альфа-коррекцией. Для этого не требуется Direct2D для проверки целевого пикселя цвета отрисовки при отрисовке текста.

Заключение

В этом разделе объясняется различия и сходство между Direct2D и DirectWrite и архитектурными мотивациями для предоставления их в качестве отдельных совместных API.