Les transitions entre images sous Lazarus avec BGRABitmap (XVI) - Utilisation des formes géométriques (suite)
par
, 12/04/2018 à 22h56 (936 Affichages)
Nous avons vu dans le précédent billet comment utiliser les formes géométriques, soit seules, soit combinées avec d'autres.
Évidemment, nous pouvons compliquer à loisir nos transitions, même à partir de figures simples comme les triangles, afin d'obtenir des transitions vraiment spectaculaires. Dans la portion de code qui suit, nous définissons une surface composée de nouveau de quatre triangles, mais en suivant les données et règles suivantes :
- un triangle isocèle dont chaque sommet au départ de la transition est à une distance d'un tiers des bords de l'image de travail (sa hauteur vaut donc un tiers de la hauteur de l'image tandis que sa base vaut un tiers de la largeur de la même image) ;
- un autre triangle isocèle de même taille, mais tête-bêche par rapport au premier, placé de telle manière que ses sommets aient la même abscisse que les sommets du premier alors que ses ordonnées sont décalées vers le bas l'image pour que l'intersection des côtés passe par le milieu de la hauteur de l'image ;
- un triangle dont deux sommets ont toujours comme coordonnées le point supérieur gauche et le point inférieur gauche de l'image tandis que le troisième sommet toujours à mi-hauteur se déplacera du bord gauche de l'image vers le premier quart de l'image sur sa droite (sa base est donc sur le côté gauche de l'image tandis que ses deux autres côtés suivent sa médiatrice) ;
- un triangle dont deux sommets ont toujours comme coordonnées le point supérieur droit et le point inférieur droit de l'image tandis que le troisième sommet toujours à mi-hauteur se déplacera du bord droit de l'image vers le dernier quart de l'image sur sa gauche dans la même proportion que le triangle précédent (il est donc le symétrique du triangle précédent par rapport au milieu de la largeur de l'image).
L'évolution de chacun des points définis est telle que l'étoile formée par les deux triangles tête-bêche doit se dilater, les deux autres triangles s'approchant d'elle jusqu'à la rejoindre.
Le code proposé est le suivant :
Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
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 procedure TMainForm.btnGoClick(Sender: TObject); // *** dessin *** var LBGRAFrom, LBGRATo, LBGRAMask: TBGRABitmap; LY, LX: Integer; LPts: array of TPointF; begin btnGo.Enabled := False; LBGRAFrom := TBGRABitmap.Create(imgResult.ClientWidth, imgResult.ClientHeight, BGRABlack); try LBGRATo := TBGRABitmap.Create(imgResult.ClientWidth, imgResult.ClientHeight, BGRABlack); try LBGRAMask := TBGRABitmap.Create(imgResult.ClientWidth, ClientHeight, BGRABlack); try fStep := 0; SetLength(LPts, 3); repeat Inc(fStep); // traitement 1 ici (source) LX := 0; LY := 0; LBGRAFrom.FillRect(ClientRect, BGRABlack); LBGRAFrom.PutImage(LX, LY, fBGRAFrom, dmDrawWithTransparency, Opacity(False)); // traitement 2 ici (destination)... // premier triangle LBGRAMask.FillRectAntialias(0, 0, imgResult.ClientWidth, imgResult.ClientHeight, BGRABlack); LPts[0].x := imgResult.ClientWidth / 3 - imgResult.ClientWidth / 3 * fStep / 100; LPts[0].y := imgResult.ClientHeight / 3 * 2 + imgResult.ClientHeight / 3 * fStep / 100; LPts[1].x := imgResult.ClientWidth / 2; LPts[1].y := imgResult.ClientHeight / 3 - imgResult.ClientHeight / 3 * fStep / 100; LPts[2].x := imgResult.ClientWidth / 3 * 2 + imgResult.ClientWidth / 3 * fStep / 100; LPts[2].y := LPts[0].y; LBGRAMask.FillPolyAntialias(LPts, BGRAWhite); // triangle opposé //LPts[0].x := imgResult.ClientWidth / 3 - imgResult.ClientWidth / 3 * fStep / 100; LPts[0].y := imgResult.ClientHeight / 2 - imgResult.ClientHeight / 2 * fStep / 100; LPts[1].x := imgResult.ClientWidth / 3 * 2 + imgResult.ClientWidth / 3 * fStep / 100; LPts[1].y := LPts[0].y; LPts[2].x := imgResult.ClientWidth / 2; LPts[2].y := imgResult.ClientHeight / 6 * 5 + imgResult.ClientHeight / 6 * fStep / 100; LBGRAMask.FillPolyAntialias(LPts, BGRAWhite); // triangle côté gauche LPts[0].x := 0; LPts[0].y := 0; LPts[1].x := imgResult.ClientWidth / 4 * fStep / 100; LPts[1].y := imgResult.ClientHeight / 2; LPts[2].x := LPts[0].x; LPts[2].y := imgResult.ClientHeight; LBGRAMask.FillPolyAntialias(LPts, BGRAWhite); //triangle côté droit LPts[0].x := imgResult.ClientWidth; //LPts[0].y := 0; LPts[1].x := imgResult.ClientWidth - imgResult.ClientWidth / 4 * fStep / 100; //LPts[1].y := imgResult.ClientHeight / 2; LPts[2].x := LPts[0].x; //LPts[2].y := imgResult.ClientHeight; LBGRAMask.FillPolyAntialias(LPts, BGRAWhite); LBGRATo.PutImage(0, 0, fBGRATo, dmSet); LBGRATo.ApplyMask(LBGRAMask); LBGRAFrom.PutImage(0, 0, LBGRATo, dmDrawWithTransparency, Opacity); LBGRAFrom.Draw(imgResult.Canvas, 0, 0); imgResult.Repaint; sleep(100 - fSpeed); until fStep = 100; finally LBGRAMask.Free; end; finally LBGRATo.Free; end; finally LBGRAFrom.Free; btnGo.Enabled := True; end; end;
Dans le code qui précède, certaines lignes de code ont été neutralisées par leur mise en commentaire : il s'agit de lignes qui aident à comprendre les calculs effectués, mais qui sont superflues puisque les bonnes valeurs sont déjà attribuées aux variables visées.
L'effet produit, nommé MegaStar, est plutôt spectaculaire et original. La vidéo suivante tente d'en rendre compte :
Dans les exemples donnés, nous nous sommes limités aux triangles, mais rien ne nous interdit de créer des polynômes plus complexes. De plus, les masques peuvent être composites en intégrant toutes les formes imaginables (par exemple*: deux rectangles, une ellipse et un octogone) dans la mesure où l'image de destination aura remplacé à la fin de la transition la totalité de l'image d'origine.
À l'occasion du travail proposé par les derniers billets, outre la richesse de FillRectAntialias, vous aurez aussi découvert de nouvelles méthodes de la classe TBGRABitmap comme ApplyMask, FillEllipseAntialias ou FillPolyAntialias (qui s'appuie sur les enregistrements de type TPointF). Votre boîte à outils s'est par conséquent bien étendue.
Par la suite, nous multiplierons les occasions d'utiliser des masques, abandonnant ainsi définitivement les premières solutions adoptées. Une prochaine étape nous verra utiliser les couches à travers une classe différente de TBGRABitmap...