IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Apprendre à créer des transitions d'image à image avec Lazarus et BGRABitmap
Par Gilles Vasseur (1)

Le , par gvasseur58

63PARTAGES

7  0 
Apprendre à créer des transitions d'image à image
Avec Lazarus et BGRABitmap

Bonjour à toutes et à tous !

La série de tutoriels inaugurée par celui que vous allez lire est destinée au programmeur soucieux d'exploiter au mieux le graphisme avec Lazarus, mais peut-être aussi à celui qui souhaite découvrir ou collecter des algorithmes pour créer des transitions d'image à image, par exemple pour un diaporama.

Les explications s'appuient sur Free Pascal et la bibliothèque BGRABitmap, tous deux des outils gratuits, open source et multiplateformes qui ont fait leurs preuves, mais elles ne se limitent pas à une illustration de leurs fonctionnalités : les techniques et les raisonnements utilisés devraient être suffisamment commentés pour être exploités par des utilisateurs d'autres langages et d'autres bibliothèques graphiques. Si vous faites partie de cette catégorie de lecteurs, c'est à partir du deuxième tutoriel que vous devriez trouver votre compte, celui en cours expliquant comment installer la bibliothèque et posant les bases d'une application de démonstration.

Si vous utilisez déjà Lazarus, sachez que ce qui va être présenté est compilable sans la moindre modification aussi bien sous Windows que sous Linux, en 32 ou 64 bits.

Pour illustrer le résultat final de la série, à savoir un composant prêt à l'emploi, voici une vidéo qui le montre en action :



Pour lire le tutoriel, c'est ici : https://gilles-vasseur.developpez.co...sitions/bgra1/

Que pensez-vous de ce tutoriel ?
Quelle utilisation faites-vous du graphisme avec Lazarus ?

Retrouvez les meilleurs cours et tutoriels pour apprendre la programmation avec Lazarus.

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de circular17
Membre confirmé https://www.developpez.com
Le 20/05/2018 à 0:41
Bonjour !

Joie de voir un tutoriel BGRABitmap.

Effectivement, le composant TImage est une surcouche qui peut ralentir l'affichage. Le scintillement peut être empêché sur la PaintBox avec DoubleBuffer, ou bien en utilisant le composant TBGRAVirtualScreen du paquet BGRAControls. Ce composant expose un évenement OnRedrawBitmap. Il est possible de demander un réaffichage différé avec DiscardBitmap ou bien de demander un réaffichage immédiat avec RedrawBitmap. Cela dit, cela demanderait de refactoriser un peu le code qui pour le moment est une boucle qui contient le dessin.

Notez que sous MacOS, dans mes souvenirs il n'est pas possible de redessiner directement sur la fenêtre. Donc une PaintBox est nécessaire. D'autre part, il n'est pas possible non plus de dessiner en dehors d'un événement OnPaint. Une boucle qui contient le dessin ne fonctionnerait donc pas pour cette plateforme. Une approche intermédiaire pourrait fonctionner : une boucle qui incrémente le temps et appelle RedrawBitmap/Invalidate et dans l'évenement le dessin en fonction de la position temporelle. Afin que cela marche sous Linux il peut être nécessaire d'appeler Application.ProcessMessages parce que le rafraîchissement des contrôles ne se fait parfois pas quand on fait Repaint mais quand on laisse la main à la boucle de message. Pas sûr que ce soit si simple au final.

En fin de compte, le plus simple qui marche pour toutes les plateformes est l'utilisation d'un Timer qui appelle DiscardBitmap ou bien Invalidate avec une PaintBox et de dessiner dans l'évenement OnPaint.

Il se peut cependant que le taux du Timer soit un peu lent. Si on veut utiliser toute la CPU disponible, on peut utiliser Application.AddOnIdleHandler / RemoveOnIdleHandler pour inscrire une procédure qui sera appelée dès que possible. Dans cette procédure on peut appeler Sleep et Invalidate, ce qui déclenchera l’événement OnPaint tout le temps.

Au sujet de la fonction StretchDraw, si le rectangle de destination a la même taille que l'image, c'est en fait équivalent à Draw. D'ailleurs en fait, la fonction de la LCL Draw appelle la fonction StretchDraw et c'est le Widgetset en dessous qui détermine en fait s'il y a lieu d'étirer ou pas. Alors je ne pense pas que la lenteur vienne de là. J'ai un vague souvenir comme quoi le composant TImage a lui-même un Timer pour se rafraichir. L'intérêt est que l'on peut dessiner sur le Canvas d'une TImage et cela ne réaffiche pas l'image pour chaque ligne tracée.

Cordialement,

Johann
2  0 
Avatar de Roland Chastain
Rédacteur/Modérateur https://www.developpez.com
Le 20/05/2018 à 12:52
@Jipété

Pas tout compris à ton message.

Je te confirme que le paquet bgracontrols.lpk existe. Où l'as-tu cherché ? Il ne fait pas partie de la bibliothèque BGRABitmap, mais de l'ensemble de composants BGRAControls, qui sont deux choses différentes.

Après il est possible que certains exemples inclus dans BGRABitmap utilisent (sans peut-être suffisamment en avertir l'utilisateur) les composants BGRAControls. Quoiqu'il en soit, le composant BGRAVirtualScreen fait partie du paquet BGRAControls, et non pas de la bibliothèque BGRABitmap.

Citation Envoyé par circular17 Voir le message
ou bien en utilisant le composant TBGRAVirtualScreen du paquet BGRAControls.
2  0 
Avatar de Jipété
Expert éminent sénior https://www.developpez.com
Le 18/05/2018 à 7:45
Citation Envoyé par BeanzMaster Voir le message
j'ai testé l'exemple 3, sous Windows c'est très fluide, mais sous Linux c'est d'une lenteur déconcertante
Linux en MV ? Si oui, je l'ai remarqué aussi avec d'autres projets : dans le host Linux le projet va très bien, et dans une MV Linux (où j'ai la dernière version de Laz/Fpc) ça rame d'une manière impressionnante.
1  0 
Avatar de BeanzMaster
Expert confirmé https://www.developpez.com
Le 18/05/2018 à 16:10
Me revoilà, le coupable c'est le TImage. En le remplaçant par un simple TPanel c'est tout bon la vitesse est identique à Windows

Voici les changements que j'ai effectué :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
type

  { TMainForm }

  TMainForm = class(TForm)
    btnGo: TButton;
    cbOpacity: TCheckBox;
    imgFrom: TImage;
    imgTo: TImage;
    lblSpeed: TLabel;
    imgResult: TPanel; // Remplacement du TImage
    tbarSpeed: TTrackBar;
    procedure btnGoClick(Sender: TObject);
    procedure cbOpacityChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure imgResultPaint(Sender: TObject);
    procedure tbarSpeedChange(Sender: TObject);
  private
    fBGRAFrom, fBGRATo: TBGRABitmap;
    LBGRATemp: TBGRABitmap; // Ajout du tampon pour l'animation
    fSpeed: Byte;
    fStep: Byte;
    fWithOpacity: Boolean;
    procedure SetSpeed(AValue: Byte);
    procedure SetWithOpacity(AValue: Boolean);
  public
    function Opacity(Up: Boolean = True): Byte;
    property Speed: Byte read fSpeed write SetSpeed default C_DefaultSpeed;
    property WithOpacity: Boolean read fWithOpacity write SetWithOpacity;
  end;    

procedure TMainForm.btnGoClick(Sender: TObject);
// *** dessin ***
var

  LY, LX: Integer;
begin
  btnGo.Enabled := False;

  try
    LX := 0;
    LY := 0;
    fStep := 0;
    repeat
      Inc(fStep);
      LBGRATemp.FillRect(ClientRect, BGRABlack);
      LBGRATemp.PutImage(0, 0, fBGRAFrom, dmSet, Opacity(False));
      // traitement ici...
     // LY := - imgResult.ClientHeight + imgResult.ClientHeight * fStep div 100; // OVERDOWN
      LBGRATemp.PutImage(LX, LY, fBGRATo, dmDrawWithTransparency, Opacity);
      imgResult.Repaint;
      Application.ProcessMessages; // Envoi du message pour redessiner le TPanel imgResult
      sleep(100 - fSpeed);
    until fStep = 100;
  finally
   //
    btnGo.Enabled := True;
  end;
end;

procedure TMainForm.FormCreate(Sender: TObject);
// *** construction des objets de travail ***
begin
  Caption := rsTestName;
  fBGRAFrom := TBGRABitmap.Create(imgFrom.Picture.Bitmap);
  BGRAReplace(fBGRAFrom, fBGRAFrom.Resample(imgResult.ClientWidth, imgResult.ClientHeight));
  fBGRATo := TBGRABitmap.Create(imgTo.Picture.Bitmap);
  BGRAReplace(fBGRATo, fBGRATo.Resample(imgResult.ClientWidth, imgResult.ClientHeight));
  fSpeed := C_DefaultSpeed;
  tbarSpeed.Position:= Speed;
  LBGRATemp := TBGRABitmap.Create(imgResult.ClientWidth, imgResult.ClientHeight, BGRABlack); // Creation du tampon
end;

procedure TMainForm.FormDestroy(Sender: TObject);
// *** destruction des objets de travail ***
begin
  fBGRAFrom.Free;
  fBGRATo.Free;
  LBGRATemp.Free; // Liberation du tampon
end;

procedure TMainForm.imgResultPaint(Sender: TObject);
begin
    LBGRATemp.Draw(imgResult.Canvas, 0, 0); // Transfert du tampon à la surface d'affichage
end;
1  0 
Avatar de gvasseur58
Responsable Lazarus & Pascal https://www.developpez.com
Le 18/05/2018 à 20:07
Le tutoriel a été mis à jour. J'ai remplacé le composant TImage par un composant TPaintBox : certaines portions de code ont donc été modifiées, mais aussi le fichier LFM et des copies d'écran. Il serait intéressant de voir pourquoi un composant aussi commun que TImage est aussi peu efficace sous Linux . Les autres épisodes de la série sont prêts : il va falloir que je vérifie que les modifications apportées n'ont pas de conséquences fâcheuses sur certaines transitions.

Il va sans dire que Jérôme a été cité pour son apport à la fin du tutoriel
1  0 
Avatar de BeanzMaster
Expert confirmé https://www.developpez.com
Le 19/05/2018 à 10:08
Citation Envoyé par gvasseur58 Voir le message
Je reviens avec d'autres expérimentations en VM. En fait, il suffit d'utiliser un TPanel (pour lequel j'ai gardé le nom imgResult), de retirer le Repaint (qui efface le canevas du composant) et d'ajouter un ProcessMessages pour récupérer les clics sur les boutons et curseurs. Pas besoin de surcharger le gestionnaire OnPaint.

Procédure :
1. Je remplace le TImage du résultat par un TPanel ou un TPaintBox renommé imgResult.
2. Je supprime imgResult.Repaint ;
3. J'ajoute Application.ProcessMessages.

Il me reste un léger problème de scintillement . J'imagine qu'il reste une question de mémoire vidéo comme l'a suggéré Jipété, mais ça ne règle pas tout...
Quelqu'un a t-il testé les exemples sur d'autres machines pur Linux ?

Gilles

[EDIT]

Pour le problème de scintillement essayes de rajouter Doublebuffered := true dans le OnCreate de la form.

Citation Envoyé par gvasseur58 Voir le message

Oui, sauf qu'il faut que je le fasse dans 40 applications .
Tu peux utiliser notepad++ pour remplacer les occurrences dans les fichiers Pas et lfm

Citation Envoyé par gvasseur58 Voir le message
Le tutoriel a été mis à jour. J'ai remplacé le composant TImage par un composant TPaintBox : certaines portions de code ont donc été modifiées, mais aussi le fichier LFM et des copies d'écran. Il serait intéressant de voir pourquoi un composant aussi commun que TImage est aussi peu efficace sous Linux . Les autres épisodes de la série sont prêts : il va falloir que je vérifie que les modifications apportées n'ont pas de conséquences fâcheuses sur certaines transitions.
Le problème du TImage est un problème entre multi-plateforme. Dans Windwos et Linux et en plus suivant le Bureau (GTK, QT...) l'affichage n'est pas gérer de la même façon. Une autre problème avec le TImage c'est qu'il contient un bitmap qui s'affiche avant le canvas. Pour pouvoir utiliser le TImage convenablement. Il faut transférer le BGRABitmap dans le Bitmap du TImage et non pas sur le Canvas. L'erreur d'affichage et la lenteur vient de la je pense. Derrière la fonction Draw de BGRABitmap se cache en réalité la fonction TCanvas.StretchDraw(); celle-ci est déja à la base moins performante sous Linux que sous Windows et c'est une fonction plutôt complexe à cause de la gestion des Widgets. Du coup il y a surement un conflit interne avec le TImage qui utilise également cette fonction pour l'affichage du bitmap sur son canvas.

Citation Envoyé par gvasseur58 Voir le message

Il va sans dire que Jérôme a été cité pour son apport à la fin du tutoriel
Merci
1  0 
Avatar de circular17
Membre confirmé https://www.developpez.com
Le 20/05/2018 à 23:11
Toute contribution de documentation est la bienvenue.
1  0 
Avatar de Roland Chastain
Rédacteur/Modérateur https://www.developpez.com
Le 20/05/2018 à 23:53
Je vous propose, au cas où cela intéresserait quelqu'un, un article sur la bibliothèque BGRABitmap que j'avais écrit l'autre année (pour un livre qui finalement n'a pas vu le jour). Johann avait eu la gentillesse de le relire, donc l'article ne devrait pas contenir trop d'erreurs.

rchastain-initiation-bgrabitmap.zip

@Jipété
C'est écrit par quelqu'un qui travaille sous Windows.


Mais le mieux est sans doute de consulter le cours écrit par Johann lui-même.
1  0 
Avatar de gvasseur58
Responsable Lazarus & Pascal https://www.developpez.com
Le 21/05/2018 à 8:43
Citation Envoyé par circular17 Voir le message
Effectivement, le composant TImage est une surcouche qui peut ralentir l'affichage. Le scintillement peut être empêché sur la PaintBox avec DoubleBuffer, ou bien en utilisant le composant TBGRAVirtualScreen du paquet BGRAControls. Ce composant expose un évenement OnRedrawBitmap. Il est possible de demander un réaffichage différé avec DiscardBitmap ou bien de demander un réaffichage immédiat avec RedrawBitmap. Cela dit, cela demanderait de refactoriser un peu le code qui pour le moment est une boucle qui contient le dessin.
Merci pour ces précisions. Je rassure tout le monde : le composant final est bâti sur TGraphicControl et utilise un TTimer. La boucle n'est qu'une solution temporaire afin de se concentrer sur les transitions elles-mêmes. De mon point de vue, il s'agit d'avoir un aperçu de l'effet obtenu, la transition réelle ayant une implémentation bien plus optimisée et complexe (par exemple, j'introduis des interpolations qui évitent la linéarité des transitions). Dans les exemples, j'ai définitivement abandonné le composant TImage (de toute façon bien trop lourd pour l'usage que j'en faisais) puisqu'il est avantageusement remplaçable par un TPaintBox. Quant aux utilisateurs d'Apple, ils pourront intervenir dans la suite de la série : je n'ai pas d'Apple (et je n'en aurai pas car je fais une allergie à cette marque ) et ne peux rien vérifier.

Citation Envoyé par circular17 Voir le message

Il se peut cependant que le taux du Timer soit un peu lent. Si on veut utiliser toute la CPU disponible, on peut utiliser Application.AddOnIdleHandler / RemoveOnIdleHandler pour inscrire une procédure qui sera appelée dès que possible. Dans cette procédure on peut appeler Sleep et Invalidate, ce qui déclenchera l’événement OnPaint tout le temps.
TTimer n'est pas ce qu'il y a de mieux, mais pour des transitions d'image à image, ce n'est en général pas un problème rédhibitoire, sauf pour les grands formats d'images. Je vais essayer, mais je crains les applications qui phagocytent toute la CPU .

Encore merci,

Gilles
1  0 
Avatar de circular17
Membre confirmé https://www.developpez.com
Le 21/05/2018 à 9:41
Effectivement Gilles tu as tout à fait raison, BGRABitmap ne nécessite pas d'être installé. Les paquets qui ont besoin d'être installés sont ceux qui ajoutent des contrôles utilisateur. Les installer permet de les voir dans la barre d'outils et d'ouvrir les projets qui les contiennent.

J'ai ajouté des liens vers les paquets qui utilisent BGRABitmap dans le wiki. Cela apportera plus une vision d'ensemble.

Il n'y a pas encore de documentation pour l'utilisation d'OpenGL avec BGRABitmap. Je vais peut-être en écrire une. C'est toujours le dilemme : passer du temps à coder des nouvelles fonctionnalités ou passer du temps à écrire de la documentation et faire attendre les demandes de fonctionnalités.

Jipété, le paquet BGRAControls a sa page ici : http://wiki.freepascal.org/BGRAControls.
Et son source est ici : https://github.com/bgrabitmap/bgracontrols

Le composant TBGRAVirtualScreen est simplement un panel sur lequel on peut dessiner, avec les événements dont je parle plus haut.

J'aime beaucoup ton tuto Roland. Les programmes d'exemples sont bienvenus. Que penses-tu de le publier en ligne ?
1  0