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


Обзор кистей

В этом обзоре описывается, как создавать и использовать объекты ID2D1SolidColorBrush, ID2D1LinearGradientBrush, ID2D1RadialGradientBrush и ID2D1BitmapBrush для рисования областей сплошными цветами, градиентами и растровыми рисунками. В него входят следующие разделы.

Предварительные требования

В этом обзоре предполагается, что вы знакомы со структурой базового приложения Direct2D, как описано в разделе Создание простого приложения Direct2D.

Типы кистей

Кисть "закрашивает" область с ее выходными данными. Разные кисти имеют различные типы выводимых данных. Direct2D предоставляет четыре типа кистей: ID2D1SolidColorBrush закрашивает область сплошным цветом, ID2D1LinearGradientBrush с линейным градиентом, ID2D1RadialGradientBrush с радиальным градиентом и ID2D1BitmapBrush с растровым рисунком.

Примечание

Начиная с Windows 8, вы также можете использовать ID2D1ImageBrush, который похож на кисть растрового изображения, но вы также можете использовать примитивы.

Все кисти наследуются от ID2D1Brush и совместно используют набор общих функций (установка и получение непрозрачности, а также преобразование кистей); Они создаются с помощью ID2D1RenderTarget и являются зависимыми от устройства ресурсами: приложение должно создавать кисти после инициализации целевого объекта отрисовки, с помощью которого будут использоваться кисти, и повторно создавать кисти, когда требуется воссоздать целевой объект отрисовки. (Дополнительные сведения о ресурсах см. в разделе Общие сведения о ресурсах.)

На следующем рисунке показаны примеры каждого из разных типов кистей.

Иллюстрация визуальных эффектов из кистей сплошного цвета, кистей линейного градиента, радиальных и растровых кистей

Основные сведения о цветах

Перед рисованием с помощью ID2D1SolidColorBrush или градиентной кисти необходимо выбрать цвета. В Direct2D цвета представлены структурой D2D1_COLOR_F (фактически это просто новое имя структуры, используемой Direct3D, D3DCOLORVALUE).

До Windows 8 D2D1_COLOR_F использует кодировку sRGB. Кодировка sRGB делит цвета на четыре компонента: красный, зеленый, синий и альфа-канал. Каждый компонент представлен значением с плавающей запятой, которое имеет нормальный диапазон от 0,0 до 1,0. Значение 0,0 указывает на полное отсутствие данного цвета, а значение 1,0 указывает на его максимальное присутствие. Для альфа-компонента значение 0,0 означает полностью прозрачный цвет, а 1,0 — полностью непрозрачный цвет.

Начиная с Windows 8, D2D1_COLOR_F также принимает кодировку scRGB. scRGB — это надмножество , которое допускает значения цвета выше 1,0 и ниже 0,0.

Чтобы определить цвет, можно использовать структуру D2D1_COLOR_F и инициализировать его поля самостоятельно или класс D2D1::ColorF , чтобы помочь в создании цвета. Класс ColorF предоставляет несколько конструкторов для определения цветов. Если альфа-значение не указано в конструкторах, по умолчанию используется значение 1.0.

  • Используйте конструктор ColorF(Enum, FLOAT), чтобы указать предопределенный цвет и значение альфа-канала. Значение альфа-канала колеблется от 0,0 до 1,0, где 0,0 представляет полностью прозрачный цвет, а 1,0 — полностью непрозрачный цвет. На следующем рисунке показано несколько предопределенных цветов и их шестнадцатеричные эквиваленты. Полный список предопределенных цветов см. в разделе Константы цвета класса ColorF .

    Иллюстрация стандартных цветов

    В следующем примере создается предопределенный цвет и он используется для указания цвета ID2D1SolidColorBrush.

hr = m_pRenderTarget->CreateSolidColorBrush(
    D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
    &m_pBlackBrush
    );
  • Используйте конструктор ColorF(FLOAT, FLOAT, FLOAT, FLOAT), чтобы указать цвет в последовательности красного, зеленого, синего и альфа-канала, где каждый элемент имеет значение от 0,0 до 1,0.

    В следующем примере указываются значения красного, зеленого, синего и альфа-цвета.

    ID2D1SolidColorBrush *pGridBrush = NULL;
    hr = pCompatibleRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f)),
        &pGridBrush
        );
  • Используйте конструктор ColorF(UINT32, FLOAT), чтобы указать шестнадцатеричное значение цвета и альфа-значение, как показано в следующем примере.
    hr = m_pRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF(0x9ACD32, 1.0f)),  
        &m_pYellowGreenBrush
        );

Режимы альфа-канала

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

Использование сплошных цветных кистей

Чтобы создать кисть сплошного цвета, вызовите метод ID2D1RenderTarget::CreateSolidColorBrush , который возвращает HRESULT и объект ID2D1SolidColorBrush . На следующем рисунке показан квадрат, обрисованный черной цветовой кистью и окрашенный сплошной цветной кистью со значением цвета 0x9ACD32.

изображение квадрата, окрашенного сплошной цветной кистью

В следующем коде показано, как создать и использовать кисть черного цвета и кисть со значением цвета 0x9ACD32 для заливки и рисования этого квадрата.

    ID2D1SolidColorBrush *m_pBlackBrush;
    ID2D1SolidColorBrush *m_pYellowGreenBrush;
if (SUCCEEDED(hr))
{
    hr = m_pRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
        &m_pBlackBrush
        );
}

// Create a solid color brush with its rgb value 0x9ACD32.
if (SUCCEEDED(hr))
{
    hr = m_pRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF(0x9ACD32, 1.0f)),  
        &m_pYellowGreenBrush
        );
}
m_pRenderTarget->FillRectangle(&rcBrushRect, m_pYellowGreenBrush);
m_pRenderTarget->DrawRectangle(&rcBrushRect, m_pBlackBrush, 1, NULL);

В отличие от других кистей, создание ID2D1SolidColorBrush является относительно недорогой операцией. Объекты ID2D1SolidColorBrush можно создавать каждый раз при отрисовки практически без влияния на производительность. Этот подход не рекомендуется использовать для кистей градиента или растрового изображения.

Использование кистей линейного градиента

ID2D1LinearGradientBrush закрашивает область с линейным градиентом, определенным вдоль линии, по оси градиента. Укажите цвета градиента и их расположение вдоль оси градиента с помощью объектов ID2D1GradientStop . Вы также можете изменить ось градиента, что позволяет создавать горизонтальные и вертикальные градиенты и изменять направление градиента. Чтобы создать кисть линейного градиента, вызовите метод ID2D1RenderTarget::CreateLinearGradientBrush .

На следующем рисунке показан квадрат, окрашенный с помощью id2D1LinearGradientBrush с двумя предопределенными цветами: Yellow и ForestGreen.

Изображение квадрата, окрашенного линейной градиентной кистью желтого и зеленого леса

Чтобы создать градиент, показанный на предыдущем рисунке, выполните следующие действия.

  1. Объявите два объекта D2D1_GRADIENT_STOP . Каждая остановка градиента задает цвет и позицию. Позиция 0,0 обозначает начало градиента, а позиция 1,0 — конец градиента.

    Следующий код создает массив из двух объектов D2D1_GRADIENT_STOP . Первая остановка задает цвет "Yellow" в позиции 0, а вторая — цвет "ForestGreen" в позиции 1.

    // Create an array of gradient stops to put in the gradient stop
    // collection that will be used in the gradient brush.
    ID2D1GradientStopCollection *pGradientStops = NULL;

    D2D1_GRADIENT_STOP gradientStops[2];
    gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Yellow, 1);
    gradientStops[0].position = 0.0f;
    gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::ForestGreen, 1);
    gradientStops[1].position = 1.0f;
  1. Создайте коллекцию ID2D1GradientStopCollection. В следующем примере вызывается метод CreateGradientStopCollection, передавая массив объектов D2D1_GRADIENT_STOP , количество остановок градиента (2), D2D1_GAMMA_2_2 для интерполяции и D2D1_EXTEND_MODE_CLAMP для режима расширения.
    // Create the ID2D1GradientStopCollection from a previously
    // declared array of D2D1_GRADIENT_STOP structs.
    hr = m_pRenderTarget->CreateGradientStopCollection(
        gradientStops,
        2,
        D2D1_GAMMA_2_2,
        D2D1_EXTEND_MODE_CLAMP,
        &pGradientStops
        );
  1. Создайте ID2D1LinearGradientBrush. В следующем примере вызывается метод CreateLinearGradientBrush и передается ему свойства кисти линейного градиента, которые содержат начальную точку (0, 0) и конечную точку в (150, 150), а градиент останавливается на предыдущем шаге.
    // The line that determines the direction of the gradient starts at
    // the upper-left corner of the square and ends at the lower-right corner.

    if (SUCCEEDED(hr))
    {
        hr = m_pRenderTarget->CreateLinearGradientBrush(
            D2D1::LinearGradientBrushProperties(
                D2D1::Point2F(0, 0),
                D2D1::Point2F(150, 150)),
            pGradientStops,
            &m_pLinearGradientBrush
            );
    }
  1. Используйте ID2D1LinearGradientBrush. В следующем примере кода используется кисть для заполнения прямоугольника.
    m_pRenderTarget->FillRectangle(&rcBrushRect, m_pLinearGradientBrush);

Дополнительные сведения об остановках градиента

D2D1_GRADIENT_STOP является базовым стандартным блоком градиентной кисти. Остановка градиента указывает цвет и положение вдоль оси градиента. Значение позиции градиента в диапазоне от 0,0 до 1,0. Чем ближе он к 0,0, тем ближе цвет к началу градиента; Чем ближе он к 1,0, тем ближе цвет к концу градиента.

На следующем рисунке показаны остановки градиента. Круг отмечает положение остановок градиента, а пунктирная линия показывает ось градиента.

Иллюстрация кисти линейного градиента с четырьмя остановками вдоль оси

Первая остановка градиента указывает желтый цвет в позиции 0,0. Вторая остановка градиента указывает красный цвет в позиции 0,25. Слева направо вдоль оси градиента цвета между этими двумя остановками постепенно изменяются с желтого на красный. Третья остановка градиента задает синий цвет в позиции 0,75. Цвета между вторым и третьим градиентом постепенно изменяются с красного на синий. Четвертая остановка градиента указывает зеленый лайм в позиции 1,0. Цвета между третьей и четвертой остановками градиента постепенно меняются с синего на зеленый.

Ось градиента

Как упоминалось ранее, остановки градиента линейной кисти градиента расположены вдоль линии, оси градиента. Ориентацию и размер строки можно указать с помощью полей startPoint и endPointструктуры D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES при создании линейной кисти градиента. После создания кисти можно настроить ось градиента, вызвав методы SetStartPoint и SetEndPoint кисти. Управляя начальной и конечной точками кисти, можно создавать горизонтальные и вертикальные градиенты, менять направление градиента и многое другое.

Например, на следующем рисунке начальная точка имеет значение (0,0), а конечная точка — (150, 50); при этом создается диагональный градиент, который начинается с левого верхнего угла и распространяется на правый нижний угол закрашиваемой области. Если для начальной точки задано значение (0, 25), а для конечной точки задано значение (150, 25), создается горизонтальный градиент. Аналогичным образом при установке начальной точки значения (75, 0) и конечной точки (75, 50) создается вертикальный градиент. При установке начальной точки значения (0, 50) и конечной точки в (150, 0) создается диагональный градиент, который начинается с левого нижнего угла и распространяется на правый верхний угол закрашиваемой области.

Иллюстрация четырех разных осей градиента в одном прямоугольнике

Использование радиальных градиентных кистей

В отличие от ID2D1LinearGradientBrush, который смешивает два или более цветов вдоль оси градиента, ID2D1RadialGradientBrush закрашивает область радиальным градиентом, который смешивает два или более цветов на эллипсе. В то время как ID2D1LinearGradientBrush определяет свою ось градиента с начальной и конечной точкой, ID2D1RadialGradientBrush определяет свой эллипс градиента, указывая центр, горизонтальные и вертикальные радиусы, а также смещение источника градиента.

Как и ID2D1LinearGradientBrush, ID2D1RadialGradientBrush использует ID2D1GradientStopCollection для указания цветов и позиций в градиенте.

На следующем рисунке показан круг, закрашенный id2D1RadialGradientBrush. Круг имеет две остановки градиента: первая указывает предопределенный цвет "Желтый" в позиции 0,0, а второй — предопределенный цвет "ForestGreen" в позиции 1,0. Градиент имеет центр (75, 75), смещение источника градиента (0, 0) и радиус x и y 75.

иллюстрация круга, окрашенного радиальной кистью градиента

В следующих примерах кода показано, как закрасить этот круг с помощью ID2D1RadialGradientBrush с двумя значениями цвета: "Yellow" в позиции 0.0 и "ForestGreen" в позиции 1.0. Аналогично созданию ID2D1LinearGradientBrush, в примере вызывается метод CreateGradientStopCollection для создания ID2D1GradientStopCollection из массива остановок градиента.

// Create an array of gradient stops to put in the gradient stop
// collection that will be used in the gradient brush.
ID2D1GradientStopCollection *pGradientStops = NULL;

D2D1_GRADIENT_STOP gradientStops[2];
gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Yellow, 1);
gradientStops[0].position = 0.0f;
gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::ForestGreen, 1);
gradientStops[1].position = 1.0f;
// Create the ID2D1GradientStopCollection from a previously
// declared array of D2D1_GRADIENT_STOP structs.
hr = m_pRenderTarget->CreateGradientStopCollection(
    gradientStops,
    2,
    D2D1_GAMMA_2_2,
    D2D1_EXTEND_MODE_CLAMP,
    &pGradientStops
    );

Чтобы создать ID2D1RadialGradientBrush, используйте метод ID2D1RenderTarget::CreateRadialGradientBrush . CreateRadialGradientBrush принимает три параметра. Первый параметр, D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES указывает центр, смещение источника градиента, а также горизонтальные и вертикальные радиусы градиента. Второй параметр — это ID2D1GradientStopCollection , описывающий цвета и их положения в градиенте, а третий параметр — адрес указателя, получающего новую ссылку ID2D1RadialGradientBrush . Некоторые перегрузки принимают дополнительный параметр, D2D1_BRUSH_PROPERTIES структуру, которая задает значение непрозрачности и преобразование для применения к новой кисти.

В следующем примере вызывается Метод CreateRadialGradientBrush, передав массив остановок градиента, а свойства кисти радиального градиента имеют значение ( 75, 75), gradientOriginOffset — (0, 0), а radiusX и radiusY — 75.

// The center of the gradient is in the center of the box.
// The gradient origin offset was set to zero(0, 0) or center in this case.
if (SUCCEEDED(hr))
{
    hr = m_pRenderTarget->CreateRadialGradientBrush(
        D2D1::RadialGradientBrushProperties(
            D2D1::Point2F(75, 75),
            D2D1::Point2F(0, 0),
            75,
            75),
        pGradientStops,
        &m_pRadialGradientBrush
        );
}

В последнем примере используется кисть для заполнения эллипса.

m_pRenderTarget->FillEllipse(ellipse, m_pRadialGradientBrush);
m_pRenderTarget->DrawEllipse(ellipse, m_pBlackBrush, 1, NULL);

Настройка радиального градиента

Различные значения для center, gradientOriginOffset, radiusX и (или) radiusY создают разные градиенты. На следующем рисунке показано несколько радиальных градиентов, которые имеют разные смещения источника градиента, создавая внешний вид света, освещающего круги под разными углами.

Иллюстрация одного и того же круга, окрашенного радиальными градиентными кисть с разными смещениями источника

Использование точечных кистей

ID2D1BitmapBrush закрашивает область растровым изображением (представленным объектом ID2D1Bitmap).

На следующем рисунке показан квадрат, окрашенный растровым изображением растения.

изображение квадрата, окрашенного растровым рисунком

В следующих примерах показано, как закрасить этот квадрат с помощью ID2D1BitmapBrush.

В первом примере инициализируется ID2D1Bitmap для использования с кистью. ID2D1Bitmap предоставляется вспомогательным методом LoadResourceBitmap, определенным в другом месте примера.

// Create the bitmap to be used by the bitmap brush.
if (SUCCEEDED(hr))
{
    hr = LoadResourceBitmap(
        m_pRenderTarget,
        m_pWICFactory,
        L"FERN",
        L"Image",
        &m_pBitmap
        );
}

Чтобы создать кисть растрового рисунка, вызовите метод ID2D1RenderTarget::CreateBitmapBrush и укажите ID2D1Bitmap , с помощью которого нужно закрасить. Метод возвращает объект HRESULT и ID2D1BitmapBrush . Некоторые перегрузки CreateBitmapBrush позволяют задавать дополнительные параметры, принимая D2D1_BRUSH_PROPERTIES и структуру D2D1_BITMAP_BRUSH_PROPERTIES .

if (SUCCEEDED(hr))
{
    hr = m_pRenderTarget->CreateBitmapBrush(
        m_pBitmap,
        &m_pBitmapBrush
        );
}

В следующем примере используется кисть для заполнения прямоугольника.

m_pRenderTarget->FillRectangle(&rcBrushRect, m_pBitmapBrush);

Настройка режимов расширения

Иногда градиент кисти градиента или растрового рисунка для кисти растрового рисунка не полностью заполняет закрашенную область.

  • Когда это происходит для ID2D1BitmapBrush, Direct2D использует параметры горизонтального (SetExtendModeX) и вертикального (SetExtendModeY) режима расширения кисти, чтобы определить, как заполнить оставшуюся область.

  • Когда это происходит для градиентной кисти, Direct2D определяет, как заполнить оставшуюся область, используя значение параметра D2D1_EXTEND_MODE , указанное при вызове CreateGradientStopCollection для создания id2D1GradientStopCollection градиента.

На следующем рисунке показаны результаты всех возможных сочетаний режимов расширения для ID2D1BitmapBrush: D2D1_EXTEND_MODE_CLAMP (CLAMP), D2D1_EXTEND_MODE_WRAP (WRAP) и D2D1_EXTEND_MIRROR (MIRROR).

иллюстрация исходного изображения и результирующие изображения из различных режимов расширения

В следующем примере показано, как задать режимы x- и y-extend кисти растрового рисунка для D2D1_EXTEND_MIRROR. Затем он закрашивает прямоугольник id2D1BitmapBrush.

m_pBitmapBrush->SetExtendModeX(D2D1_EXTEND_MODE_MIRROR);
m_pBitmapBrush->SetExtendModeY(D2D1_EXTEND_MODE_MIRROR);

m_pRenderTarget->FillRectangle(exampleRectangle, m_pBitmapBrush);

Он создает выходные данные, как показано на следующем рисунке.

иллюстрация исходного изображения и полученного изображения после зеркального отображения направления X и Y

Преобразование кистей

При рисовании кистью она закрашивает координатное пространство целевого объекта отрисовки. Кисти не располагаются автоматически в соответствии с закрашенным объектом; По умолчанию они начинают рисование в источнике (0, 0) целевого объекта отрисовки.

Градиент, определенный ID2D1LinearGradientBrush , можно переместить в целевую область, задав начальную и конечную точки. Аналогичным образом можно переместить градиент, определенный id2D1RadialGradientBrush , изменив его центр и радиусы.

Чтобы выровнять содержимое ID2D1BitmapBrush по закрашиваемой области, можно использовать метод SetTransform для преобразования растрового рисунка в нужное расположение. Это преобразование влияет только на кисть; он не влияет на другое содержимое, нарисованное целевым объектом отрисовки.

На следующих рисунках показан эффект использования ID2D1BitmapBrush для заполнения прямоугольника, расположенного в (100, 100). На рисунке слева показан результат заполнения прямоугольника без преобразования кисти: растровое изображение рисуется в источнике целевого объекта отрисовки. В результате в прямоугольнике отображается только часть растрового изображения. На рисунке справа показан результат преобразования ID2D1BitmapBrush таким образом, чтобы его содержимое сместилось на 50 пикселей вправо и на 50 пикселей вниз. Растровое изображение заполняет прямоугольник.

иллюстрация квадрата, окрашенного кистью растрового рисунка без преобразования кисти и путем преобразования кисти

В следующем коде показано, как это сделать. Сначала примените преобразование к ID2D1BitmapBrush, переместив кисть на 50 пикселей вправо по оси X и на 50 пикселей вниз по оси Y. Затем используйте ID2D1BitmapBrush , чтобы заполнить прямоугольник, который имеет верхний левый угол в (100, 100) и правый нижний угол в (200, 200).

// Create the bitmap to be used by the bitmap brush.
if (SUCCEEDED(hr))
{
    hr = LoadResourceBitmap(
        m_pRenderTarget,
        m_pWICFactory,
        L"FERN",
        L"Image",
        &m_pBitmap
        );
   
}

if (SUCCEEDED(hr))
{
    hr = m_pRenderTarget->CreateBitmapBrush(
        m_pBitmap,
        &m_pBitmapBrush
        );
}

D2D1_RECT_F rcTransformedBrushRect = D2D1::RectF(100, 100, 200, 200);

// Demonstrate the effect of transforming a bitmap brush.
m_pBitmapBrush->SetTransform(
     D2D1::Matrix3x2F::Translation(D2D1::SizeF(50,50))
     );

// To see the content of the rcTransformedBrushRect, comment
// out this statement.
m_pRenderTarget->FillRectangle(
     &rcTransformedBrushRect, 
     m_pBitmapBrush
     );

m_pRenderTarget->DrawRectangle(rcTransformedBrushRect, m_pBlackBrush, 1, NULL);