Developing with Graphics/fr
│
Deutsch (de) │
English (en) │
español (es) │
français (fr) │
italiano (it) │
日本語 (ja) │
한국어 (ko) │
Nederlands (nl) │
português (pt) │
русский (ru) │
slovenčina (sk) │
中文(中国大陆) (zh_CN) │
中文(台灣) (zh_TW) │
Cette page sera un lancement de tutoriels concernant la manipulation d'images et autres graphiques. Car je ne suis pas un programmeur en graphisme , j'invite tous ceux qui sont prêt à partager leur compétence! Ajouter juste un lien à la prochaine section , ajouter une page et créer votre propre article WiKi .
Sur cette page quelques informations générales seront fournies .
D'autres articles sur le graphisme
- GLScene - Un portage de la librairie graphique visual OpenGL GLScene
- TAChart - composant de diagrammes pour Lazarus
- PascalMagick - une API facile à utiliser pour s'interfacer avec ImageMagick, une suite libre de logiciel multiplateforme pour créer , éditer, et composer des images bitmap.
- PlotPanel - un composant de traçage et de tracage de diagrammes pour des graphes animés
- LazRGBGraphics - Un paquet pour de rapides manipulations de pixels et de traitement d'image en mémoire (comme le balayage de ligne).
- bruit de Perlin - Un article concernant l'emploi de bruit de Perlin avec les applications LCL( Lazarus Component Library).
Travailler avec TBitmap
La première chose à se rappeler est que Lazarus est censé être indépendant de la plateforme, ainsi toutes méthodes utilisant la fonctionnalité de l'API Windows sont inadmissibles. Ainsi une méthode comme ScanLine n'est pas supportée par Lazarus parce qu'il est destiné à être indépendant du dispositif de bitmap et utilise des fonctions de la bibliothèque GDI32.dll.
Considérer que si vous n'indiquez pas la taille et la largeur du votre TBitmap il aura le standard , lequel est tout à fait petit .
Un exemple de fading
Supposez que vous voulez faire disparaître(fading) une image . Dans Delphi vous pourriez faire quelque chose comme :
type
PRGBTripleArray = ^TRGBTripleArray;
TRGBTripleArray = array[0..32767] of TRGBTriple;
procedure TForm1.FadeIn(aBitMap: TBitMap);
var
Bitmap, BaseBitmap: TBitmap;
Row, BaseRow: PRGBTripleArray;
x, y, step: integer;
begin
Bitmap := TBitmap.Create;
try
Bitmap.PixelFormat := pf32bit; // or pf24bit
Bitmap.Assign(aBitMap);
BaseBitmap := TBitmap.Create;
try
BaseBitmap.PixelFormat := pf32bit;
BaseBitmap.Assign(Bitmap);
for step := 0 to 32 do begin
for y := 0 to (Bitmap.Height - 1) do begin
BaseRow := BaseBitmap.Scanline[y];
Row := Bitmap.Scanline[y];
for x := 0 to (Bitmap.Width - 1) do begin
Row[x].rgbtRed := (step * BaseRow[x].rgbtRed) shr 5;
Row[x].rgbtGreen := (step * BaseRow[x].rgbtGreen) shr 5; // Fading
Row[x].rgbtBlue := (step * BaseRow[x].rgbtBlue) shr 5;
end;
end;
Form1.Canvas.Draw(0, 0, Bitmap);
InvalidateRect(Form1.Handle, nil, False);
RedrawWindow(Form1.Handle, nil, 0, RDW_UPDATENOW);
end;
finally
BaseBitmap.Free;
end;
finally
Bitmap.Free;
end;
end;
Cette fonction dans Lazarus pourrait être implémentée comme:
procedure TForm1.FadeIn(ABitMap: TBitMap);
var
SrcIntfImg, TempIntfImg: TLazIntfImage;
ImgHandle,ImgMaskHandle: HBitmap;
FadeStep: Integer;
px, py: Integer;
CurColor: TFPColor;
TempBitmap: TBitmap;
begin
SrcIntfImg:=TLazIntfImage.Create(0,0);
SrcIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);
TempIntfImg:=TLazIntfImage.Create(0,0);
TempIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);
TempBitmap:=TBitmap.Create;
for FadeStep:=1 to 32 do begin
for py:=0 to SrcIntfImg.Height-1 do begin
for px:=0 to SrcIntfImg.Width-1 do begin
CurColor:=SrcIntfImg.Colors[px,py];
CurColor.Red:=(CurColor.Red*FadeStep) shr 5;
CurColor.Green:=(CurColor.Green*FadeStep) shr 5;
CurColor.Blue:=(CurColor.Blue*FadeStep) shr 5;
TempIntfImg.Colors[px,py]:=CurColor;
end;
end;
TempIntfImg.CreateBitmap(ImgHandle,ImgMaskHandle,false);
TempBitmap.Handle:=ImgHandle;
TempBitmap.MaskHandle:=ImgMaskHandle;
Canvas.Draw(0,0,TempBitmap);
end;
SrcIntfImg.Free;
TempIntfImg.Free;
TempBitmap.Free;
end;
Le code Lazarus sur cette page a été pris du projet $LazarusPath/examples/lazintfimage/fadein1.lpi. Ainsi si vous voulez une initiation avec la programmation de graphiques jetez un coup d'oeil plus étroit sur cet exemple .
Tracer des bitmaps en couleurs transparentes
Un nouveau dispositif , implémenté avec Lazarus 0.9.11, sont les bitmap en couleur transparentes. les fichiers Bitmap (*.BMP)ne peuvent stocker aucune information sur la transparence , mais ils peuvent fonctionner comme s'ils en avaient si vous choisissez une couleur sur eux pour représenter le secteur transparent . C'est un tour courant utilisé dans les applications Win32.
L'exemple suivant charge un Bitmap à partir d'une ressource Windows, choisit une couleur pour être transparente (clFuchsia) et le dessine ensuite sur le canvas.
procedure MyForm.MyButtonOnClick(Sender: TObject); var buffer: THandle; bmp: TBitmap; memstream: TMemoryStream; begin bmp := TBitmap.Create; buffer := Windows.LoadBitmap(hInstance, MAKEINTRESOURCE(ResourceID)); if (buffer = 0) then exit; // Error loading the bitmap bmp.Handle := buffer; memstream := TMemoryStream.create; try bmp.SaveToStream(memstream); memstream.position := 0; bmp.LoadFromStream(memstream); finally memstream.free; end; bmp.Transparent := True; bmp.TransparentColor := clFuchsia; MyCanvas.Draw(0, 0, bmp); bmp.Free; // Release allocated resource end;
Noter les opérations de mémoire effectuées avec TMemoryStream. Elles sont nécessaires pour assurer le chargement correct de l'image .
Faire une capture d'image de l'écran
Depuis Lazarus 0.9.16 vous pouvez employer LCL pour faire des captures d'images de l'écran de manière multi-plateforme. Le code d'exemple suivant le fait (fonctionne avec gtk2 et win32, mais non gtk1 actuellement ):
uses LCLIntf, LCLType; ... var MyBitmap: TBitmap ScreenDC: HDC; begin MyBitmap := TBitmap.Create; ScreenDC := GetDC(0); MyBitmap.LoadFromDevice(ScreenDC); ReleaseDC(ScreenDC); ...
graphiques en mouvement - Comment éviter le clignotement
Beaucoup de programmes dessinent leur sortie sur le GUI sous forme de graphiques 2D. Si ces graphiques ont besoin de changer rapidement vous ferez face bientôt à un problème : les graphiques changeant rapidement clignotent souvent sur l'écran . Ceci se produit quand les utilisateurs voient parfois des images entières et parfois seulement quand c'est dessiné partiellement. Cela se produit parce que le procédé d'affichage a besoin de temps .
Mais comment puis je éviter le clignotement et obtenir la meilleure vitesse de dessin ? Naturellement vous pourriez travailler avec l'accélération matérielle en utilisant OpenGL , mais cette approche est tout à fait lourde pour de petits programmes ou de vieux ordinateurs . Ce tutoriel se concentrera sur la façon de dessiner sur un TCanvas. Si vous avez besoin d'aide avec OpenGL, jeter un coup d'oeil sur l'exemple qui vient avec Lazarus. Vous pouvez également employer le gamepack d'A.J. Venter, qui fourni un canvas à double-tampon et un composant de sprite .
Maintenant nous examinerons les options que nous avons pour dessiner un canvas :
- Dessiner sur un Timage
- Dessiner sur l'evènement OnPaint de la fiche, un contrôle TPaintBox ou un autre
- Créer un contrôle habituel qui se dessine lui même
- Employer le gamepack d'A.J. Venter
Dessiner sur un Timage
Un TImage se compose en 2 parts : un TGraphic, habituellement un TBitmap, contenant l'image persistante et l'aire visuelle , laquelle est peinte à chaque OnPaint. Redimensionner le TImage ne redimensionne pas le bitmap. Le graphique (ou bitmap) est accessible par l'intermédiaire de Image1.Picture.Graphic (ou Image1.Picture.Bitmap). La canvas est Image1.Picture.Bitmap.Canvas. Le canvas de l'aire visuelle d'une TImage est seulement accessible pendant Image1.OnPaint via Image1.Canvas.
Important: Ne jamais employer le OnPaint de l'évênement Image1 pour dessiner le graphique/bitmap d'une TImage. Le graphique d'une TImage est en mémoire tampon aussi tout que vous devez faire est de dessiner vers elle de n'importe où et le changement est là pour toujours . Cependant, si vous redessinez constamment , l'image clignotera . Dans ce cas-ci vous pouvez essayer les autres options . Dessin sur une TImage est considéré comme étant plus lent que les autres approches .
Redimensionner le bitmap d'une TImage
Note : Ne pas employer ceci pendant OnPaint.
with Image1.Picture.Bitmap do begin Width:=100; Height:=120; end;
Peindre sur le bitmap d'une TImage
Note: Ne pas employer ceci pendant OnPaint.
with Image1.Picture.Bitmap.Canvas do begin // fill the entire bitmap with red Brush.Color:=clRed; FillRect(0,0,Width,Height); end;
Note: À l'intérieur de Image1.OnPaint l' Image1.Canvas pointe vers l'aire visible volatile. En dehors de Image1.OnPaint l' Image1.Canvas pointe vers Image1.Picture.Bitmap.Canvas.
Un autre exemple :
procedure TForm1.BitBtn1Click(Sender: TObject);
var
x, y: Integer;
begin
// Draws the backgroung
MyImage.Canvas.Pen.Color := clWhite;
MyImage.Canvas.Rectangle(0, 0, Image.Width, Image.Height);
// Draws squares
MyImage.Canvas.Pen.Color := clBlack;
for x := 1 to 8 do
for y := 1 to 8 do
MyImage.Canvas.Rectangle(Round((x - 1) * Image.Width / 8), Round((y - 1) * Image.Height / 8),
Round(x * Image.Width / 8), Round(y * Image.Height / 8));
end;
Peindre sur l'aire visuelle volatile de TImage
Vous pouvez seulement peindre sur ce secteur pendant OnPaint. OnPaint est éventuellement appellé automatiquement par la LCL quand le secteur a été infirmé . Vous pouvez infirmer manuellement le secteur avec Image1.Invalidate. Ceci n'appellera pas immédiatement OnPaint et vous pouvez appeler Invalidate autant de fois que vous le voulez .
procedure TForm.Image1Paint(Sender: TObject); begin with Image1.Canvas do begin // paint a line Pen.Color:=clRed; Line(0,0,Width,Height); end; end;
Dessiner sur l'évênement OnPaint
Dans ce cas tout le dessin doit être fait sur l'évênement OnPaint de la fiche. Il ne reste pas sur le tampon, comme sur la TImage.
Créer un contrôle à soi qui se dessine lui-même
Créer une comtôle à soi à l'avantage de structurer votre code et vous pouvez réutiliser la commande . Cette approche est très rapide,mais elle peut toujours produire du clignotement si vous ne dessinez pas sur un TBitmap en premier et dessiner ensuite sur le canvas. Dans ce cas il n'est pas besoin d'employer l'évênement OnPaint du contrôle.
Voici ici un exemple de contrôle à soi:
uses
Classes, SysUtils, Controls, Graphics, LCLType;
type
TMyDrawingControl = class(TCustomControl)
public
procedure EraseBackground(DC: HDC); override;
procedure Paint; override;
end;
implementation
procedure TMyDrawingControl.EraseBackground(DC: HDC);
begin
// Uncomment this to enable default background erasing
//inherited EraseBackground(DC);
end;
procedure TMyDrawingControl.Paint;
var
x, y: Integer;
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
// Initializes the Bitmap Size
Bitmap.Height := Height;
Bitmap.Width := Width;
// Draws the background
Bitmap.Canvas.Pen.Color := clWhite;
Bitmap.Canvas.Rectangle(0, 0, Width, Height);
// Draws squares
Bitmap.Canvas.Pen.Color := clBlack;
for x := 1 to 8 do
for y := 1 to 8 do
Bitmap.Canvas.Rectangle(Round((x - 1) * Width / 8), Round((y - 1) * Height / 8),
Round(x * Width / 8), Round(y * Height / 8));
Canvas.Draw(0, 0, Bitmap);
finally
Bitmap.Free;
end;
inherited Paint;
end;
and how we create it on the form:
procedure TMyForm.FormCreate(Sender: TObject);
begin
MyDrawingControl:= TMyDrawingControl.Create(Self);
MyDrawingControl.Height := 400;
MyDrawingControl.Width := 500;
MyDrawingControl.Top := 0;
MyDrawingControl.Left := 0;
MyDrawingControl.Parent := Self;
MyDrawingControl.DoubleBuffered := True;
end;
just don´t forget to destroy it:
procedure TMyForm.FormDestroy(Sender: TObject);
begin
MyDrawingControl.Free;
end;
Paramétrer le Top et le Left à zéro n'est pas nécessaire , puisque c'est la position standard, mais est fait ainsi pour renforcer l'endroi où la commande sera mise .
"MyDrawingControl.Parent := Self;" est très important et vous ne verrez pas votre contrôle si vous ne faites pas ainsi .
"MyDrawingControl.DoubleBuffered := True;" est nécessaire pour éviter le clignotement sur Windows . Il n'a aucun effet sur gtk.
Employer le gamepack d'A.J. Venter
The gamepack approach is to draw everything to one double-buffered canvas, which only gets updated to the visible canvas when you are ready. This takes quite a bit of code, but it has the advantage of being able to do large rapidly changing scenes with multiple sprites on them. If you wish to use this approach, you may be interested in A.J. Venter's gamepack, a set of components for game development in Lazarus, which provides a double-buffered display area component as well as a sprite component, designed to integrate well with one another. You can get gamepack via subversion:
svn co svn://silentcoder.co.za/lazarus/gamepack