Présentation des pinceaux

Cette vue d’ensemble explique comment créer et utiliser des objets ID2D1SolidColorBrush, ID2D1LinearGradientBrush, ID2D1RadialGradientBrush et ID2D1BitmapBrush pour peindre des zones avec des couleurs unie, des dégradés et des bitmaps. Elle contient les sections suivantes.

Prérequis

Cette vue d’ensemble suppose que vous êtes familiarisé avec la structure d’une application Direct2D de base, comme décrit dans Créer une application Direct2D simple.

Types de pinceau

Un pinceau « peint » une zone avec sa sortie. Des pinceaux différents ont différents types de sortie. Direct2D fournit quatre types de pinceaux : ID2D1SolidColorBrush peint une zone avec une couleur unie, ID2D1LinearGradientBrush avec un dégradé linéaire, ID2D1RadialGradientBrush avec un dégradé radial et ID2D1BitmapBrush avec un bitmap.

Notes

À partir de Windows 8, vous pouvez également utiliser ID2D1ImageBrush, qui est similaire à un pinceau bitmap, mais vous pouvez également utiliser des primitives.

Tous les pinceaux héritent d’ID2D1Brush et partagent un ensemble de fonctionnalités communes (définition et obtention de l’opacité, et transformation des pinceaux) ; ils sont créés par ID2D1RenderTarget et sont des ressources dépendantes de l’appareil : votre application doit créer des pinceaux après avoir initialisé la cible de rendu avec laquelle les pinceaux seront utilisés, et recréer les pinceaux chaque fois que la cible de rendu doit être recréée. (Pour plus d’informations sur les ressources, consultez Vue d’ensemble des ressources.)

L’illustration suivante montre des exemples de chacun des différents types de pinceau.

illustration des effets visuels des pinceaux de couleur unie, des pinceaux de dégradé linéaire, des pinceaux de dégradé radial et des pinceaux bitmap

Principes de base des couleurs

Avant de peindre avec un pinceau ID2D1SolidColorBrush ou dégradé, vous devez choisir des couleurs. Dans Direct2D, les couleurs sont représentées par la structure D2D1_COLOR_F (qui n’est en fait qu’un nouveau nom pour la structure utilisée par Direct3D, D3DCOLORVALUE).

Avant Windows 8, D2D1_COLOR_F utilise l’encodage sRGB. L’encodage sRGB divise les couleurs en quatre composants : rouge, vert, bleu et alpha. Chaque composant est représenté par une valeur de virgule flottante comprise dans une plage standard de 0 à 1. La valeur 0 indique l’absence complète de cette couleur, tandis que la valeur 1 indique que cette couleur est entièrement présente. Pour le composant alpha, 0 représente une couleur totalement transparente, et 1 une couleur totalement opaque.

À partir de Windows 8, D2D1_COLOR_F accepte également l’encodage scRGB. scRGB est un sur-ensemble de qui autorise des valeurs de couleur supérieures à 1.0 et inférieures à 0.0.

Pour définir une couleur, vous pouvez utiliser la structure D2D1_COLOR_F et initialiser ses champs vous-même, ou vous pouvez utiliser la classe D2D1::ColorF pour vous aider à créer la couleur. La classe ColorF fournit plusieurs constructeurs pour définir des couleurs. Si la valeur alpha n’est pas spécifiée dans les constructeurs, la valeur par défaut est 1.0.

  • Utilisez le constructeur ColorF(Enum, FLOAT) pour spécifier une couleur prédéfinie et une valeur de canal alpha. Une valeur de canal alpha varie de 0,0 à 1,0, où 0,0 représente une couleur entièrement transparente et 1.0 représente une couleur entièrement opaque. L’illustration suivante montre plusieurs couleurs prédéfinies et leurs équivalents hexadécimaux. Pour obtenir la liste complète des couleurs prédéfinies, consultez la section Constantes de couleur de la classe ColorF .

    illustration de couleurs prédéfinies

    L’exemple suivant crée une couleur prédéfinie et l’utilise pour spécifier la couleur d’un ID2D1SolidColorBrush.

hr = m_pRenderTarget->CreateSolidColorBrush(
    D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
    &m_pBlackBrush
    );
  • Utilisez le constructeur ColorF(FLOAT, FLOAT, FLOAT, FLOAT) pour spécifier une couleur dans la séquence d’un rouge, vert, bleu et alpha, où chaque élément a une valeur comprise entre 0,0 et 1,0.

    L’exemple suivant spécifie les valeurs rouge, verte, bleue et alpha d’une couleur.

    ID2D1SolidColorBrush *pGridBrush = NULL;
    hr = pCompatibleRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f)),
        &pGridBrush
        );
  • Utilisez le constructeur ColorF(UINT32, FLOAT) pour spécifier la valeur hexadécimale d’une couleur et une valeur alpha, comme illustré dans l’exemple suivant.
    hr = m_pRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF(0x9ACD32, 1.0f)),  
        &m_pYellowGreenBrush
        );

Modes alpha

Quel que soit le mode alpha de la cible de rendu avec laquelle vous utilisez un pinceau, D2D1_COLOR_F valeurs sont toujours interprétées comme alpha droite.

Utilisation de pinceaux de couleur unie

Pour créer un pinceau de couleur unie, appelez la méthode ID2D1RenderTarget::CreateSolidColorBrush , qui retourne un objet HRESULT et un objet ID2D1SolidColorBrush . L’illustration suivante montre un carré qui est caressé avec un pinceau de couleur noire et peint avec un pinceau de couleur unie qui a la valeur de couleur de 0x9ACD32.

illustration d’un carré peint avec un pinceau de couleur unie

Le code suivant montre comment créer et utiliser un pinceau de couleur noire et un pinceau avec une valeur de couleur de 0x9ACD32 pour remplir et dessiner ce carré.

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

Contrairement à d’autres pinceaux, la création d’un ID2D1SolidColorBrush est une opération relativement peu coûteuse. Vous pouvez créer des objets ID2D1SolidColorBrush chaque fois que vous effectuez un rendu avec peu ou pas d’impact sur les performances. Cette approche n’est pas recommandée pour les pinceaux dégradés ou bitmap.

Utilisation de pinceaux de dégradé linéaire

Un objet ID2D1LinearGradientBrush peint une zone avec un dégradé linéaire défini le long d’une ligne, l’axe de dégradé. Vous spécifiez les couleurs du dégradé et leur emplacement le long de l’axe du dégradé à l’aide d’objets ID2D1GradientStop . Vous pouvez également modifier l’axe du dégradé, ce qui vous permet de créer un dégradé horizontal et vertical et d’inverser la direction du dégradé. Pour créer un pinceau de dégradé linéaire, appelez la méthode ID2D1RenderTarget::CreateLinearGradientBrush .

L’illustration suivante montre un carré qui est peint avec un ID2D1LinearGradientBrush qui a deux couleurs prédéfinies, « Jaune » et « ForestGreen ».

illustration d’un carré peint avec un pinceau dégradé linéaire de jaune et vert forêt

Pour créer le dégradé illustré dans l’illustration précédente, procédez comme suit :

  1. Déclarez deux objets D2D1_GRADIENT_STOP . Chaque point de dégradé spécifie une couleur et une position. Une position de 0,0 indique le début du dégradé, tandis qu’une position de 1.0 indique la fin du dégradé.

    Le code suivant crée un tableau de deux objets D2D1_GRADIENT_STOP . Le premier arrêt spécifie la couleur « Jaune » à la position 0, et le deuxième arrêt spécifie la couleur « ForestGreen » à la position 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. Créez un ID2D1GradientStopCollection. L’exemple suivant appelle CreateGradientStopCollection, en transmettant le tableau d’objets D2D1_GRADIENT_STOP , le nombre d’arrêts de dégradé (2), D2D1_GAMMA_2_2 pour l’interpolation et D2D1_EXTEND_MODE_CLAMP pour le mode étendu.
    // 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. Créez l’ID2D1LinearGradientBrush. L’exemple suivant appelle la méthode CreateLinearGradientBrush et lui transmet les propriétés de pinceau de dégradé linéaire qui contiennent le point de début à (0, 0) et le point de fin à (150, 150), et le dégradé s’arrête à l’étape précédente.
    // 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. Utilisez id2D1LinearGradientBrush. L’exemple de code suivant utilise le pinceau pour remplir un rectangle.
    m_pRenderTarget->FillRectangle(&rcBrushRect, m_pLinearGradientBrush);

En savoir plus sur les arrêts de dégradé

Le D2D1_GRADIENT_STOP est le bloc de construction de base d’un pinceau dégradé. Un point de dégradé spécifie la couleur et la position le long de l’axe du dégradé. La valeur de la position de dégradé est comprise entre 0,0 et 1,0. Plus elle est proche de 0,0, plus la couleur est proche du début du dégradé ; plus elle est proche de 1.0, plus la couleur est proche de la fin du dégradé.

L’illustration suivante met en évidence les arrêts de dégradé. Le cercle marque la position des arrêts de dégradé et une ligne en pointillés montre l’axe du dégradé.

illustration d’un pinceau de dégradé linéaire avec quatre arrêts le long de l’axe

Le premier point de dégradé spécifie la couleur jaune à une position de 0,0. Le deuxième point de dégradé spécifie la couleur rouge à une position de 0,25. De gauche à droite le long de l’axe dégradé, les couleurs entre ces deux arrêts passent progressivement du jaune au rouge. Le troisième point de dégradé spécifie la couleur bleue à une position de 0,75. Les couleurs entre les deuxième et troisième dégradés passent progressivement du rouge au bleu. Le quatrième point de dégradé spécifie le vert lime à une position de 1.0. Les couleurs entre les troisième et quatrième dégradés passent progressivement du bleu au vert vert vert.

Axe du dégradé

Comme mentionné précédemment, les points de dégradé d’un pinceau de dégradé linéaire sont positionnés le long d’une ligne, l’axe du dégradé. Vous pouvez spécifier l’orientation et la taille de la ligne à l’aide des champs startPoint et endPoint de la structure D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lorsque vous créez un pinceau en dégradé linéaire. Une fois que vous avez créé un pinceau, vous pouvez ajuster l’axe du dégradé en appelant les méthodes SetStartPoint et SetEndPoint du pinceau. En manipulant le point de début et le point de fin du pinceau, vous pouvez créer des dégradés horizontaux et verticaux, inverser la direction du dégradé, et bien plus encore.

Par exemple, dans l’illustration suivante, le point de début est défini sur (0,0) et le point de fin sur (150, 50) ; cela crée un dégradé diagonal qui commence dans le coin supérieur gauche et s’étend jusqu’au coin inférieur droit de la zone en cours de peinture. Lorsque vous définissez le point de début sur (0, 25) et le point de fin sur (150, 25), un dégradé horizontal est créé. De même, définir le point de début sur (75, 0) et le point de fin sur (75, 50) crée un dégradé vertical. Le fait de définir le point de début sur (0, 50) et le point de fin sur (150, 0) crée un dégradé diagonal qui commence dans le coin inférieur gauche et s’étend jusqu’au coin supérieur droit de la zone en cours de peinture.

illustration de quatre axes de dégradé différents sur le même rectangle

Utilisation de pinceaux de dégradé radial

Contrairement à un ID2D1LinearGradientBrush, qui mélange deux couleurs ou plus le long d’un axe de dégradé, un ID2D1RadialGradientBrush peint une zone avec un dégradé radial qui mélange deux couleurs ou plus sur une ellipse. Alors qu’un ID2D1LinearGradientBrush définit son axe de dégradé avec un point de départ et un point de fin, un ID2D1RadialGradientBrush définit son ellipse de dégradé en spécifiant un rayon central, horizontal et vertical, et un décalage d’origine de dégradé.

Comme un ID2D1LinearGradientBrush, un ID2D1RadialGradientBrush utilise un ID2D1GradientStopCollection pour spécifier les couleurs et les positions dans le dégradé.

L’illustration suivante montre un cercle peint avec un ID2D1RadialGradientBrush. Le cercle a deux points de dégradé : le premier spécifie une couleur prédéfinie « Jaune » à une position de 0,0, et le second spécifie une couleur prédéfinie « ForestGreen » à une position de 1.0. Le dégradé a un centre de (75, 75), un décalage d’origine de dégradé de (0, 0) et un rayon x et y de 75.

illustration d’un cercle peint avec un pinceau dégradé radial

Les exemples de code suivants montrent comment peindre ce cercle avec un ID2D1RadialGradientBrush qui a deux points de couleur : « Jaune » à une position de 0,0 et « ForestGreen » à une position de 1,0. Semblable à la création d’un ID2D1LinearGradientBrush, l’exemple appelle CreateGradientStopCollection pour créer un ID2D1GradientStopCollection à partir d’un tableau de points de dégradé.

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

Pour créer un ID2D1RadialGradientBrush, utilisez la méthode ID2D1RenderTarget::CreateRadialGradientBrush . CreateRadialGradientBrush prend trois paramètres. Le premier paramètre, un D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES spécifie le centre, le décalage d’origine du dégradé et les rayons horizontaux et verticaux du dégradé. Le deuxième paramètre est un ID2D1GradientStopCollection qui décrit les couleurs et leurs positions dans le dégradé, et le troisième paramètre est l’adresse du pointeur qui reçoit la nouvelle référence ID2D1RadialGradientBrush . Certaines surcharges prennent un paramètre supplémentaire, une structure D2D1_BRUSH_PROPERTIES qui spécifie une valeur d’opacité et une transformation à appliquer au nouveau pinceau.

L’exemple suivant appelle CreateRadialGradientBrush, en passant le tableau de points de dégradé, et les propriétés de pinceau de dégradé radial qui ont la valeur centrale définie sur (75, 75), le gradientOriginOffset défini sur (0, 0) et radiusX et radiusY définis sur 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
        );
}

Le dernier exemple utilise le pinceau pour remplir une ellipse.

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

Configuration d’un dégradé radial

Des valeurs différentes pour center, gradientOriginOffset, radiusX et/ou radiusY produisent des dégradés différents. L’illustration suivante montre plusieurs dégradés radials qui ont des décalages d’origine différents, créant l’apparence de la lumière éclairant les cercles sous différents angles.

illustration du même cercle peint avec des pinceaux dégradés radials avec des décalages d’origine différents

Utilisation de pinceaux bitmap

Un objet ID2D1BitmapBrush peint une zone avec une image bitmap (représentée par un objet ID2D1Bitmap ).

L’illustration suivante montre un carré peint avec une bitmap d’une plante.

illustration d’un carré peint avec bitmap végétale

Les exemples suivants montrent comment peindre ce carré avec un objet ID2D1BitmapBrush.

Le premier exemple initialise un ID2D1Bitmap pour une utilisation avec le pinceau. ID2D1Bitmap est fourni par une méthode d’assistance, LoadResourceBitmap, définie ailleurs dans l’exemple.

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

Pour créer le pinceau bitmap, appelez la méthode ID2D1RenderTarget::CreateBitmapBrush et spécifiez l’ID2D1Bitmap avec lequel peindre. La méthode retourne un objet HRESULT et un objet ID2D1BitmapBrush . Certaines surcharges CreateBitmapBrush vous permettent de spécifier des options supplémentaires en acceptant une D2D1_BRUSH_PROPERTIES et une structure D2D1_BITMAP_BRUSH_PROPERTIES .

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

L’exemple suivant utilise le pinceau pour remplir un rectangle.

m_pRenderTarget->FillRectangle(&rcBrushRect, m_pBitmapBrush);

Configuration des modes d’extension

Parfois, le dégradé d’un pinceau de dégradé ou la bitmap d’un pinceau bitmap ne remplit pas complètement la zone en cours de peinture.

L’illustration suivante montre les résultats de chaque combinaison possible des modes d’extension pour un OBJET ID2D1BitmapBrush : D2D1_EXTEND_MODE_CLAMP (CLAMP), D2D1_EXTEND_MODE_WRAP (WRAP) et D2D1_EXTEND_MIRROR (MIRROR).

illustration d’une image d’origine et des images résultantes de différents modes d’extension

L’exemple suivant montre comment définir les modes d’extension x et y du pinceau bitmap sur D2D1_EXTEND_MIRROR. Il peint ensuite le rectangle avec l’ID2D1BitmapBrush.

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

m_pRenderTarget->FillRectangle(exampleRectangle, m_pBitmapBrush);

Il produit une sortie comme indiqué dans l’illustration suivante.

illustration d’une image d’origine et de l’image résultante après mise en miroir de la direction x et de la direction y

Transformation des pinceaux

Lorsque vous peignez avec un pinceau, il peint dans l’espace de coordonnées de la cible de rendu. Les pinceaux ne se positionnent pas automatiquement pour s’aligner sur l’objet peint ; par défaut, ils commencent à peindre à l’origine (0, 0) de la cible de rendu.

Vous pouvez « déplacer » le dégradé défini par un ID2D1LinearGradientBrush vers une zone cible en définissant son point de début et son point de fin. De même, vous pouvez déplacer le dégradé défini par un ID2D1RadialGradientBrush en modifiant son centre et ses rayons.

Pour aligner le contenu d’un ID2D1BitmapBrush sur la zone en cours de peinture, vous pouvez utiliser la méthode SetTransform pour traduire la bitmap à l’emplacement souhaité. Cette transformation affecte uniquement le pinceau ; elle n’affecte aucun autre contenu dessiné par la cible de rendu.

Les illustrations suivantes montrent l’effet de l’utilisation d’un ID2D1BitmapBrush pour remplir un rectangle situé à (100, 100). L’illustration de gauche montre le résultat du remplissage du rectangle sans transformer le pinceau : l’image bitmap est dessinée à l’origine de la cible de rendu. Par conséquent, seule une partie de la bitmap apparaît dans le rectangle. L’illustration de droite montre le résultat de la transformation de l’ID2D1BitmapBrush afin que son contenu soit déplacé de 50 pixels vers la droite et de 50 pixels vers le bas. La bitmap remplit désormais le rectangle.

illustration d’un carré peint avec un pinceau bitmap sans transformer le pinceau et en transformant le pinceau

Le code suivant montre comment effectuer cette opération. Appliquez d’abord une traduction à l’ID2D1BitmapBrush, en déplaçant le pinceau de 50 pixels à droite le long de l’axe x et de 50 pixels vers le bas le long de l’axe y. Ensuite, utilisez l’ID2D1BitmapBrush pour remplir le rectangle qui a le coin supérieur gauche à (100, 100) et le coin inférieur droit à (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);