Changer l’alpha d’un PNG à l’exécution

Cet article montrera comment changer le canal alpha d’une image de type PNG lors de l’exécution d’un programme codé avec C++Builder.

En premier lieu, il faut créer un nouveau projet auquel on ajoute un composant TTrackBar. C’est avec ce contrôle que l’on changera la transparence de l’image. Il sera gradué de 0 à 100, car il représente un pourcentage d’opacité.

Transparence d'un PNG

Dans le constructeur de la Form, on ajoute le code suivant:

    OriginalImage = new TPngImage();
    OriginalImage->LoadFromFile("../tux.png");

    TrackBar1->Align = alBottom;// Le composant est aligné au bas de la fenêtre
    TrackBar1->Min = 0;         // Le minimum est 0%
    TrackBar1->Max = 100;       // Le maximum est 100%
    TrackBar1->Position = 0;    // Position de départ à 0%
    TrackBar1->Frequency = 5;   // Marque de graduation à tout les 5 incréments
    TrackBar1->PageSize = 5;    // Déplacement par bonds de 5
    TrackBar1->ShowSelRange = false;// La zone sélectionnée n'est pas affichée

    DoubleBuffered = true; // Évite le scintillement lors d'un redimensionnement

Les lignes 1 et 2 servent à créer un objet TPngImage qui servira à garder en mémoire l’image originale. Le but de OriginalImage est de ne pas avoir à recharger l’image à chaque fois que le TTrackBar se déplacera. Dans ce code, on charge l’image directement du disque dur avec LoadFromFile, mais on aurait pu la charger à partir des ressources du programme.

Dans l’évènement OnDestroy de la fenêtre, on ajoute cette ligne pour libérer la mémoire allouée par OriginalImage:

    delete OriginalImage;

Dans votre fichier d’en-tête, ajoutez le code suivant dans la section private:

    TPngImage *OriginalImage;
    void __fastcall SetTransparency(TPngImage *PngImage, float TransPct);

Maintenant, voici la pièce de résistance, la méthode qui change l’alpha d’un PNG:

void __fastcall TForm1::SetTransparency(TPngImage *PngImage, float TransPct)
{
    int x, y;
    Byte *DestAlpha, Alpha;
    float Pct = TransPct / 100.0f;
    for(y = 0; y < PngImage->Height; y++)
    {
        DestAlpha = (Byte *)PngImage->AlphaScanline[y];
        for(x = 0; x < PngImage->Width; x++)
        {
            Alpha = RoundTo(Pct * DestAlpha[x], 0);
            if((DestAlpha[x] - Alpha) < 0)
                DestAlpha[x] = 0;
            else
                DestAlpha[x] -= Alpha;
        }
    }
}

Le premier paramètre d’entrée est un objet de type TPngImage qui sera modifié. Le deuxième paramètre est une valeur en pourcentage, donc on attend une valeur entre 0 et 100. 0 rendra l’image complètement opaque et celle-ci ne sera donc pas modifiée tandis qu’à 100, elle est complètement transparente.

La méthode AlphaScanline lit une ligne de numérisation contenant le canal alpha et renvoie un pointeur sur la mémoire contenant cette ligne.

Puisque la fonction RoundTo est utilisée pour arrondir, il faut ajouter cet entête:

#include <Math.hpp>

À cause de problème de scintillement avec un TImage, l’image sera dessinée directement sur le Canvas de la fenêtre. Voici le code à ajouter à l’évènement OnChange du TTrackBar:

    TPngImage *ImageToProcess = new TPngImage();
    Graphics::TBitmap *TempImage = new Graphics::TBitmap();

    ImageToProcess->Assign(OriginalImage);
    SetTransparency(ImageToProcess, TrackBar1->Position);

    TempImage->Canvas->Brush->Color = Form1->Color;
    TempImage->SetSize(OriginalImage->Width, OriginalImage->Height);
    TempImage->Canvas->Draw(0, 0, ImageToProcess);

    Canvas->Draw(Width/2 - TempImage->Width/2,
        Height/2 - TempImage->Height/2 - TrackBar1->Height, TempImage);

    delete ImageToProcess;
    delete TempImage;

Deux images temporaires seront créées. ImageToProcess est de type TPngImage et on lui assigne l’image originale et on la modifie ensuite en appelant SetTransparency. TempImage est un TBitmap qui sert à la double mise en mémoire tampon. On y dessine l’arrière plan de la couleur de la fenêtre et ensuite on y dessine ImageToProcess. C’est cette image que l’on dessine sur le Canvas au centre de la fenêtre avec la méthode Draw.

Dans l’évènement OnPaint de la fenêtre, on ajoute ce code pour que l’image soit toujours présente:

    TrackBar1Change(NULL);

Dans l’évènement OnResize de la fenêtre, on doit redessiner l’image pour qu’elle reste centrée:

    Invalidate();

Voilà ce qui met fin à l’article. Vous pouvez maintenant vous amuser avec la barre graduée afin de changer l’opacité de l’image.

Je vous laisse avec une ligne de code qui pourrait vous être pratique si vous désirez seulement changer à une reprise le canal alpha d’un PNG dans un TImage:

SetTransparency((TPngImage *)Image1->Picture->Graphic, 75);