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


Обзор маски непрозрачности

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

Необходимые условия

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

Что такое маска непрозрачности?

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

Существует несколько способов применения маски непрозрачности:

  • Используйте метод ID2D1RenderTarget::FillOpacityMask. Метод FillOpacityMask красит прямоугольную область целевого объекта отрисовки, а затем применяет маску непрозрачности, определенную растровым изображением. Используйте этот метод, если маска непрозрачности является растровым изображением, и вы хотите заполнить прямоугольную область.
  • Используйте метод ID2D1RenderTarget::FillGeometry. Метод FillGeometry заполняет внутреннюю часть геометрии с помощью указанного ID2D1BitmapBrush, а затем применяет маску непрозрачности, определенную кистью. Используйте этот метод, если вы хотите применить маску непрозрачности к геометрии или вы хотите использовать кисть в качестве маски непрозрачности.
  • Используйте ID2D1Layer для применения маски непрозрачности. Используйте этот подход, если вы хотите применить маску непрозрачности к группе содержимого рисования, а не только к одной фигуре или изображению. Для получения подробной информации см. обзор слоев .

Использование растрового изображения в качестве маски непрозрачности с помощью метода FillOpacityMask

Метод FillOpacityMask красит прямоугольную область целевого объекта отрисовки, а затем применяет маску непрозрачности, определяемую ID2D1Bitmap. Используйте этот метод, если у вас есть растровое изображение, которое вы хотите использовать в качестве маски непрозрачности для прямоугольной области.

На следующей схеме показан эффект применения маски непрозрачности (ID2D1Bitmap с изображением цветка) к ID2D1BitmapBrush с изображением растения папоротника. Полученное изображение представляет собой растровое изображение растения, обрезанное по форме цветка.

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

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

Первый пример загружает следующее растровое изображение m_pBitmapMaskдля использования в качестве маски растрового изображения. На следующем рисунке показано, как выглядят выходные данные. Обратите внимание, что, хотя непрозрачная часть растрового изображения отображается черной, сведения о цвете в растровом рисунке не влияют на маску непрозрачности; Используются только сведения о непрозрачности каждого пикселя в растровом рисунке. Полностью непрозрачные пиксели в этой растровой карте были окрашены черным только для иллюстрирующих целей.

иллюстрация маски растрового изображения цветка

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

            if (SUCCEEDED(hr))
            {
                hr = LoadResourceBitmap(
                    m_pRenderTarget,
                    m_pWICFactory,
                    L"BitmapMask",
                    L"Image",
                    &m_pBitmapMask
                    );
            }

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

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

            if (SUCCEEDED(hr))
            {
                D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = 
                    D2D1::BitmapBrushProperties(
                    D2D1_EXTEND_MODE_CLAMP,
                    D2D1_EXTEND_MODE_CLAMP,
                    D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
                    );
                hr = m_pRenderTarget->CreateBitmapBrush(
                    m_pFernBitmap,
                    propertiesXClampYClamp,
                    &m_pFernBitmapBrush
                    );


            }

Теперь, когда определена маска непрозрачности и кисть, можно использовать метод FillOpacityMask в методе отрисовки приложения. При вызове метода FillOpacityMask необходимо указать тип маски непрозрачности, которую вы используете: D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2D1_OPACITY_MASK_CONTENT_TEXT_NATURALи D2D1_OPACITY_MASK_CONTENT_TEXT_GDI_COMPATIBLE. Значения этих трех типов см. в D2D1_OPACITY_MASK_CONTENT.

Заметка

Начиная с Windows 8, D2D1_OPACITY_MASK_CONTENT не требуется. См. метод ID2D1DeviceContext::FillOpacityMask, который не имеет параметра D2D1_OPACITY_MASK_CONTENT.

 

Следующий пример задает режим сглаживания целевого объекта отрисовки D2D1_ANTIALIAS_MODE_ALIASED, чтобы маска непрозрачности работала правильно. Затем он вызывает метод FillOpacityMask и передает его маску непрозрачности (m_pBitmapMask), кисть, к которой применяется маска непрозрачности (m_pFernBitmapBrush), тип содержимого внутри маски непрозрачности (D2D1_OPACITY_MASK_CONTENT_GRAPHICS) и область для рисования. На следующем рисунке показаны выходные данные, которые получаются.

иллюстрация растения папоротника с примененной маской непрозрачности

        D2D1_RECT_F rcBrushRect = D2D1::RectF(5, 5, 155, 155);


        // D2D1_ANTIALIAS_MODE_ALIASED must be set for FillOpacityMask to function properly
        m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
        m_pRenderTarget->FillOpacityMask(
            m_pBitmapMask,
            m_pFernBitmapBrush,
            D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
            &rcBrushRect
            );
        m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);

Код был опущен в этом примере.

Использование кисти в качестве маски непрозрачности с помощью метода FillGeometry

В предыдущем разделе описано, как использовать ID2D1Bitmap в качестве маски непрозрачности. Direct2D также предоставляет метод ID2D1RenderTarget::FillGeometry, который позволяет дополнительно указать кисть в качестве маски непрозрачности при заполнении ID2D1Geometry. Это позволяет создавать маски непрозрачности из градиентов (с помощью ID2D1LinearGradientBrush или ID2D1RadialGradientBrush) и растровых карт (с помощью ID2D1Bitmap).

Метод FillGeometry принимает три параметра:

  • Первый параметр, ID2D1Geometry, определяет фигуру для рисования.
  • Второй параметр, ID2D1Brush, указывает кисть, используемую для рисования геометрии. Этот параметр должен быть ID2D1BitmapBrush, у которого режимы расширения по осям x и y установлены на D2D1_EXTEND_MODE_CLAMP.
  • Третий параметр, ID2D1Brush, указывает кисть, используемую в качестве маски непрозрачности. Эта кисть может быть ID2D1LinearGradientBrush, ID2D1RadialGradientBrushили ID2D1BitmapBrush. (Технически вы можете использовать ID2D1SolidColorBrush, но использование сплошной кисти цвета в качестве маски непрозрачности не дает интересных результатов.)

В следующих разделах описывается использование ID2D1LinearGradientBrush и объектов ID2D1RadialGradientBrush в качестве маски непрозрачности.

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

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

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

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

  1. Определите содержимое для маскирования. В следующем примере создается ID2D1BitmapBrush, m_pLinearFadeFlowersBitmap. Для режима расширения x и y для m_pLinearFadeFlowersBitmap задано значение D2D1_EXTEND_MODE_CLAMP, чтобы его можно было использовать с маской непрозрачности с помощью метода FillGeometry.

    if (SUCCEEDED(hr))
    {
        // Create the bitmap to be used by the bitmap brush.
        hr = LoadResourceBitmap(
            m_pRenderTarget,
            m_pWICFactory,
            L"LinearFadeFlowers",
            L"Image",
            &m_pLinearFadeFlowersBitmap
            );
    }
    
    if (SUCCEEDED(hr))
        {
            D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = 
                D2D1::BitmapBrushProperties(
                D2D1_EXTEND_MODE_CLAMP,
                D2D1_EXTEND_MODE_CLAMP,
                D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
                );
    
    C++
                    if (SUCCEEDED(hr))
                    {
                        hr = m_pRenderTarget->CreateBitmapBrush(
                            m_pLinearFadeFlowersBitmap,
                            propertiesXClampYClamp,
                            &m_pLinearFadeFlowersBitmapBrush
                            );
                    }
    C++
                }
  2. Определите маску непрозрачности. В следующем примере кода создается диагональная линейная градиентная кисть (m_pLinearGradientBrush), которая переходит из полностью непрозрачного черного цвета в положение 0 до полностью прозрачного белого в положение 1.

                if (SUCCEEDED(hr))
                {
                    ID2D1GradientStopCollection *pGradientStops = NULL;

                    static const D2D1_GRADIENT_STOP gradientStops[] =
                    {
                        {   0.f,  D2D1::ColorF(D2D1::ColorF::Black, 1.0f)  },
                        {   1.f,  D2D1::ColorF(D2D1::ColorF::White, 0.0f)  },
                    };

                    hr = m_pRenderTarget->CreateGradientStopCollection(
                        gradientStops,
                        2,
                        &pGradientStops);


                    if (SUCCEEDED(hr))
                    {
                        hr = m_pRenderTarget->CreateLinearGradientBrush(
                            D2D1::LinearGradientBrushProperties(
                                D2D1::Point2F(0, 0),
                                D2D1::Point2F(150, 150)),
                            pGradientStops,
                            &m_pLinearGradientBrush);
                    }

    
                pGradientStops->Release();
                }
  1. Используйте метод FillGeometry. В последнем примере метод FillGeometry использует кисть содержимого для заполнения ID2D1RectangleGeometry (m_pRectGeo) с помощью ID2D1BitmapBrush (m_pLinearFadeFlowersBitmap) и применяет маску непрозрачности (m_pLinearGradientBrush).
            m_pRenderTarget->FillGeometry(
                m_pRectGeo, 
                m_pLinearFadeFlowersBitmapBrush, 
                m_pLinearGradientBrush
                );

Код был опущен в этом примере.

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

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

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

В первом примере создается ID2D1BitmapBrush, m_pRadialFadeFlowersBitmapBrush. Чтобы его можно было использовать с маской непрозрачности методом FillGeometry, для режима расширения x и y для m_pRadialFadeFlowersBitmapBrush установлены значения D2D1_EXTEND_MODE_CLAMP.

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


            if (SUCCEEDED(hr))
            {
                D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = 
                    D2D1::BitmapBrushProperties(
                    D2D1_EXTEND_MODE_CLAMP,
                    D2D1_EXTEND_MODE_CLAMP,
                    D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
                    );
C++
                if (SUCCEEDED(hr))
                {
                    hr = m_pRenderTarget->CreateBitmapBrush(
                        m_pLinearFadeFlowersBitmap,
                        propertiesXClampYClamp,
                        &m_pLinearFadeFlowersBitmapBrush
                        );
                }
C++
            }

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

            if (SUCCEEDED(hr))
            {
                ID2D1GradientStopCollection *pGradientStops = NULL;

                static const D2D1_GRADIENT_STOP gradientStops[] =
                {
                    {   0.f,  D2D1::ColorF(D2D1::ColorF::Black, 1.0f)  },
                    {   1.f,  D2D1::ColorF(D2D1::ColorF::White, 0.0f)  },
                };

                hr = m_pRenderTarget->CreateGradientStopCollection(
                    gradientStops,
                    2,
                    &pGradientStops);




                if (SUCCEEDED(hr))
                {
                    hr = m_pRenderTarget->CreateRadialGradientBrush(
                        D2D1::RadialGradientBrushProperties(
                            D2D1::Point2F(75, 75),
                            D2D1::Point2F(0, 0),
                            75,
                            75),
                        pGradientStops,
                        &m_pRadialGradientBrush);
                }
                pGradientStops->Release();
            }

Последний пример кода использует ID2D1BitmapBrush (m_pRadialFadeFlowersBitmapBrush) и маску непрозрачности (m_pRadialGradientBrush) для заполнения ID2D1RectangleGeometry (m_pRectGeo).

        m_pRenderTarget->FillGeometry(
            m_pRectGeo,
            m_pRadialFadeFlowersBitmapBrush, 
            m_pRadialGradientBrush
            );

Код был опущен в этом примере.

Примените маску непрозрачности к слою

При вызове PushLayer для отправки ID2D1Layer в целевой объект рендеринга можно использовать структуру D2D1_LAYER_PARAMETERS для использования кисти в качестве маски непрозрачности. В следующем примере кода в качестве маски прозрачности используется ID2D1RadialGradientBrush.

HRESULT DemoApp::RenderWithLayerWithOpacityMask(ID2D1RenderTarget *pRT)
{   

    HRESULT hr = S_OK;

    // Create a layer.
    ID2D1Layer *pLayer = NULL;
    hr = pRT->CreateLayer(NULL, &pLayer);

    if (SUCCEEDED(hr))
    {
        pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 250));

        // Push the layer with the content bounds.
        pRT->PushLayer(
            D2D1::LayerParameters(
                D2D1::InfiniteRect(),
                NULL,
                D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
                D2D1::IdentityMatrix(),
                1.0,
                m_pRadialGradientBrush,
                D2D1_LAYER_OPTIONS_NONE),
            pLayer
            );

        pRT->DrawBitmap(m_pBambooBitmap, D2D1::RectF(0, 0, 190, 127));

        pRT->FillRectangle(
            D2D1::RectF(25.f, 25.f, 50.f, 50.f), 
            m_pSolidColorBrush
            );
        pRT->FillRectangle(
            D2D1::RectF(50.f, 50.f, 75.f, 75.f),
            m_pSolidColorBrush
            ); 
        pRT->FillRectangle(
            D2D1::RectF(75.f, 75.f, 100.f, 100.f),
            m_pSolidColorBrush
            );    
 
        pRT->PopLayer();
    }
    SafeRelease(&pLayer);
   
    return hr;
    
}

Для получения дополнительной информации об использовании слоев см. "Обзор слоев" .

Обзор кистей

Обзор уровней