Visão geral de máscaras da opacidade

Este tópico descreve como usar bitmaps e pincéis para definir máscaras de opacidade. Ele contém as seguintes seções:

Pré-requisitos

Essa visão geral pressupõe que você esteja familiarizado com operações básicas de desenho Direct2D, conforme descrito no passo a passo Criar um aplicativo Direct2D simples. Você também deve estar familiarizado com os diferentes tipos de pincéis, conforme descrito na Visão geral de pincéis.

O que é uma máscara de opacidade?

Uma máscara de opacidade é uma máscara, descrita por um pincel ou bitmap, que é aplicada a outro objeto para tornar esse objeto parcial ou completamente transparente. Uma máscara de opacidade usa informações de canal alfa para especificar como os pixels de origem do objeto são misturados ao destino de destino final. As partes transparentes da máscara indicam as áreas em que a imagem subjacente está oculta, enquanto as partes opacas da máscara indicam onde o objeto mascarado está visível.

Há várias maneiras de aplicar uma máscara de opacidade:

  • Use o método ID2D1RenderTarget::FillOpacityMask . O método FillOpacityMask pinta uma região retangular de um destino de renderização e aplica uma máscara de opacidade, definida por um bitmap. Use esse método quando a máscara de opacidade for um bitmap e você quiser preencher uma região retangular.
  • Use o método ID2D1RenderTarget::FillGeometry . O método FillGeometry pinta o interior da geometria com o ID2D1BitmapBrush especificado e aplica uma máscara de opacidade, definida por um pincel. Use esse método quando quiser aplicar uma máscara de opacidade a uma geometria ou quiser usar um pincel como uma máscara de opacidade.
  • Use um ID2D1Layer para aplicar uma máscara de opacidade. Use essa abordagem quando quiser aplicar uma máscara de opacidade a um grupo de conteúdo de desenho, não apenas a uma única forma ou imagem. Para obter detalhes, consulte a Visão geral das camadas.

Usar um Bitmap como uma Máscara de Opacidade com o método FillOpacityMask

O método FillOpacityMask pinta uma região retangular de um destino de renderização e aplica uma máscara de opacidade, definida por um ID2D1Bitmap. Use esse método quando você tiver um bitmap que deseja usar como uma máscara de opacidade para uma região retangular.

O diagrama a seguir mostra um efeito da aplicação da máscara de opacidade (um ID2D1Bitmap com uma imagem de uma flor) a um ID2D1BitmapBrush com uma imagem de uma planta de samambaia. A imagem resultante é um bitmap de uma planta recortada na forma de flor.

diagrama de um bitmap de flor usado como uma máscara de opacidade em uma imagem de uma planta de samambaia

Os exemplos de código a seguir mostram como isso é feito.

O primeiro exemplo carrega o bitmap a seguir, m_pBitmapMask, para uso como uma máscara de bitmap. A ilustração a seguir mostra a saída produzida. Observe que, embora a parte opaca do bitmap pareça preta, as informações de cor no bitmap não têm efeito sobre a máscara de opacidade; somente as informações de opacidade de cada pixel no bitmap são usadas. Os pixels totalmente opacos neste bitmap foram coloridos em preto apenas para fins ilustrativos.

ilustração da máscara de bitmap de flor

Neste exemplo, o ID2D1Bitmap é carregado por um método auxiliar, LoadResourceBitmap, definido em outro lugar no exemplo.

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

O próximo exemplo define o pincel, m_pFernBitmapBrush, ao qual a máscara de opacidade é aplicada. Este exemplo usa um ID2D1BitmapBrush que contém uma imagem de uma samambaia, mas você pode usar um ID2D1SolidColorBrush, ID2D1LinearGradientBrush ou ID2D1RadialGradientBrush . A ilustração a seguir mostra a saída produzida.

ilustração do bitmap usado pelo pincel de bitmap

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


            }

Agora que a máscara de opacidade e o pincel estão definidos, você pode usar o método FillOpacityMask no método de renderização do aplicativo. Ao chamar o método FillOpacityMask , você deve especificar o tipo de máscara de opacidade que está usando: D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2D1_OPACITY_MASK_CONTENT_TEXT_NATURAL e D2D1_OPACITY_MASK_CONTENT_TEXT_GDI_COMPATIBLE. Para obter os significados desses três tipos, consulte D2D1_OPACITY_MASK_CONTENT.

Observação

Começando com Windows 8, a D2D1_OPACITY_MASK_CONTENT não é necessária. Consulte o método ID2D1DeviceContext::FillOpacityMask , que não tem nenhum parâmetro D2D1_OPACITY_MASK_CONTENT .

 

O próximo exemplo define o modo de suavização do destino de renderização como D2D1_ANTIALIAS_MODE_ALIASED para que a máscara de opacidade funcione corretamente. Em seguida, ele chama o método FillOpacityMask e passa a ele a máscara de opacidade (m_pBitmapMask), o pincel ao qual a máscara de opacidade é aplicada (m_pFernBitmapBrush), o tipo de conteúdo dentro da máscara de opacidade (D2D1_OPACITY_MASK_CONTENT_GRAPHICS) e a área a ser pintada. A ilustração a seguir mostra a saída produzida.

ilustração da imagem da planta samambaia com uma máscara de opacidade aplicada

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

O código foi omitido neste exemplo.

Usar um pincel como uma máscara de opacidade com o método FillGeometry

A seção anterior descreveu como usar um ID2D1Bitmap como uma máscara de opacidade. Direct2D também fornece o método ID2D1RenderTarget::FillGeometry, que permite especificar opcionalmente o pincel como uma máscara de opacidade ao preencher um ID2D1Geometry. Isso permite que você crie máscaras de opacidade de gradientes (usando ID2D1LinearGradientBrush ou ID2D1RadialGradientBrush) e bitmaps (usando ID2D1Bitmap).

O método FillGeometry usa três parâmetros:

As seções a seguir descrevem como usar objetos ID2D1LinearGradientBrush e ID2D1RadialGradientBrush como máscaras de opacidade.

Usar um pincel de gradiente linear como uma máscara de opacidade

O diagrama a seguir mostra o efeito de aplicar um pincel de gradiente linear a um retângulo que é preenchido com um bitmap de flores.

diagrama de um bitmap de flor com um pincel de gradiente linear aplicado

As etapas a seguir descrevem como recriar esse efeito.

  1. Defina o conteúdo a ser mascarado. O exemplo a seguir cria um ID2D1BitmapBrush, m_pLinearFadeFlowersBitmap. Os modos de extensão x e y para m_pLinearFadeFlowersBitmap são definidos como D2D1_EXTEND_MODE_CLAMP para que possam ser usados com uma máscara de opacidade pelo método 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. Defina a máscara de opacidade. O próximo exemplo de código cria um pincel de gradiente linear diagonal (m_pLinearGradientBrush) que desaparece de preto totalmente opaco na posição 0 para branco completamente transparente na posição 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. Use o método FillGeometry . O exemplo final usa o método FillGeometry para o pincel de conteúdo para preencher um ID2D1RectangleGeometry (m_pRectGeo) com um ID2D1BitmapBrush (m_pLinearFadeFlowersBitmap) e aplica uma máscara de opacidade (m_pLinearGradientBrush).
            m_pRenderTarget->FillGeometry(
                m_pRectGeo, 
                m_pLinearFadeFlowersBitmapBrush, 
                m_pLinearGradientBrush
                );

O código foi omitido neste exemplo.

Usar um pincel de gradiente radial como uma máscara de opacidade

O diagrama a seguir mostra o efeito visual da aplicação de um pincel de gradiente radial a um retângulo que é preenchido com um bitmap de folhagem.

diagrama de um bitmap de folhagem com um pincel de gradiente radial aplicado

O primeiro exemplo cria um ID2D1BitmapBrush, m_pRadialFadeFlowersBitmapBrush. Para que ele possa ser usado com uma máscara de opacidade pelo método FillGeometry , os modos de extensão x e y para m_pRadialFadeFlowersBitmapBrush são definidos como 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++
            }

O próximo exemplo define o pincel de gradiente radial que será usado como a máscara de opacidade.

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

O exemplo de código final usa o ID2D1BitmapBrush (m_pRadialFadeFlowersBitmapBrush) e a máscara de opacidade (m_pRadialGradientBrush) para preencher um ID2D1RectangleGeometry (m_pRectGeo).

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

O código foi omitido neste exemplo.

Aplicar uma Máscara de Opacidade a uma camada

Ao chamar PushLayer para efetuar push de um ID2D1Layer para um destino de renderização, você pode usar a estrutura D2D1_LAYER_PARAMETERS para aplicar um pincel como uma máscara de opacidade. O exemplo de código a seguir usa um ID2D1RadialGradientBrush como uma máscara de opacidade.

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

Para obter mais informações sobre como usar camadas, consulte a Visão geral das camadas.

Visão geral de pincéis

Visão geral das camadas