Sign in Join
Wiki copytemporary

Developing with Graphics/de: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Developing with Graphics/de

OldNewLine
1+Diese Seite beschreibt die grundlegenden Klassen und Techniken im Hinblick auf das Zeichnen von Grafiken mit Lazarus. Andere, speziellere Themen sind in gesonderten Artikeln zu finden.
2+
3+## Andere Grafikartikel
4+
5+### 2D Grafik
6+
7+- [[ZenGL]] - cross-platform game development library using OpenGL.
8+- [[BGRABitmap/de|BGRABitmap]] - Zeichnen von Formen und Bitmaps mit Transparenzinformationen, direkte Zugriff auf Pixels, etc.
9+- [[LazRGBGraphics]] - A package for fast in memory image processing and pixel manipulations (like scan line).
10+- [[fpvectorial]] - Offers support to read, modify and write vectorial images.
11+- [[Double Gradient/de|Double Gradient]] - Zeichnet 'doppelte Farbverläufe' und 'n-fache Farbverläufe' ganz einfach in Bitmaps.
12+- [[Gradient Filler]] - TGradientFiller is the best way to create custom n gradients in Lazarus.
13+- [[PascalMagick]] - ein einfach zu verwendendes [[Glossary|API]] für die Kopplung mit [ImageMagick](http://www.imagemagick.org), einer freien Multiplattform-Softwaresammlung um Bitmaps zu erzeugen, zu bearbeiten und zu entwerfen.
14+- [[Sample Graphics]] - graphics gallery created with Lazarus and drawing tools
15+- [[Fast direct pixel access]] - speed comparison of some methods for direct bitmap pixel access
16+
17+### 3D Grafik
18+
19+- [[GLScene/de|GLScene]] - Eine Portierung der visuellen OpenGL-Graphikbibliothek [GLScene](http://www.glscene.org)
20+
21+### Diagramme
22+
23+- [[TAChart/de|TAChart]] - Diagrammkomponente für Lazarus
24+- [[PlotPanel/de|PlotPanel]] - Eine Komponente zum Darstellen( Plotting / Charting) von animierten Graphen. Ähnlich wie TAChart.
25+- [[Perlin Noise]] - Ein Artikel über die Verwendung von Perlin Noise in LCL Anwendungen.
26+
27+## Arbeiten mit TBitmap
28+
29+Das Objekt 'TBitmap' speichert eine Bitmap, auf die Sie zeichnen können, bevor Sie sie am Bildschirm anzeigen. Wenn Sie eine Bitmap erzeugen, müssen Sie deren Höhe und Breite immer angeben, ansonsten sind sie 0 und es wird nichts gezeichnet.
30+
31+### Direkter Zugriff auf Pixel
32+
33+Für einen direkten Zugriff auf Bitmaps können Sie externe Bibliotheken einsetzen, wie z. B. [[BGRABitmap]], [[LazRGBGraphics]] und [[Current conversion projects|Graphics32]]. Einen Vergleich verschiedener Methoden des Zugriffs auf ein Pixel finden Sie unter [[Fast direct pixel access]].
34+
35+Bei einigen Betriebssystemen werden die Daten einer Bitmap nicht im Arbeitsspeicher abgelegt, deswegen kann man auf sie auch nicht direkt zugreifen. Da Lazarus plattformunabhängig sein soll, stellt die Klasse TBitmap auch keine Eigenschaft wie Scanline zur Verfügung. Es gibt eine Funktion 'GetDataLineStart', äquivalent zu Scanline, aber nur für Memory-Images wie TLazIntfImage, das intern TRawImage benutzt.
36+
37+Auf den Punkt gebracht, können Sie eine Bitmap nur indirekt verändern, indem Sie eine Memory-Bitmap modifizieren und diese dann in eine zeichenbare Bitmap konvertieren. Dieser Vorgang ist natürlich langsamer als der direkte Zugriff.
38+
39+### Zeichnen von farbigen transparenten Bitmaps
40+
41+Ein neues Feature, implementiert in Lazarus 0.9.11, sind farbtransparente Bitmaps. Bitmap-Dateien (*.BMP) können keine Informationen über Transparenz speichern, aber Sie können dies zur Laufzeit umgehen, indem Sie eine Transparenz-Farbe wählen, mit der Sie die transparenten Bereiche markieren. Bei Win32-Anwendungen ist dies ein üblicher Trick.
42+
43+Das folgende Beispiel lädt eine Bitmap aus einer Windows Ressource, wählt eine Farbe (clFuchsia) für die Transparenz aus und zeichnet dann auf die Zeichenfläche (Canvas).
44+
45+``` pascal
46+procedure MyForm.MyButtonOnClick(Sender: TObject);
47+var
48+ buffer: THandle;
49+ bmp: TBitmap;
50+ memstream: TMemoryStream;
51+begin
52+ bmp := TBitmap.Create;
53+
54+ buffer := Windows.LoadBitmap(hInstance, MAKEINTRESOURCE(ResourceID));
55+
56+ if (buffer = 0) then exit; // Fehler beim Laden der Bitmap
57+
58+ bmp.Handle := buffer;
59+ memstream := TMemoryStream.create;
60+ try
61+ bmp.SaveToStream(memstream);
62+ memstream.position := 0;
63+ bmp.LoadFromStream(memstream);
64+ finally
65+ memstream.free;
66+ end;
67+
68+ bmp.Transparent := True;
69+ bmp.TransparentColor := clFuchsia;
70+
71+ MyCanvas.Draw(0, 0, bmp);
72+
73+ bmp.Free; // Gibt belegte Ressourcen frei
74+end;
75+```
76+
77+Beachten Sie, dass die Speicheroperationen mit [[doc:rtl/classes/tmemorystream.html|TMemoryStream]] ausgeführt werden. Sie sind notwendig, um das korrekte Laden des Bildes sicherzustellen.
78+
79+### Ein Bildschirmfoto erstellen
80+
81+Seit Lazarus 0.9.16 können Sie die LCL verwenden, um plattformunabhängig Bildschirmfotos aufzunehmen. Der folgende Beispielcode zeigt es (funktioniert unter GTK2 und Win32, aber gegenwärtig nicht unter GTK1):
82+
83+``` pascal
84+uses Graphics, LCLIntf, LCLType;
85+
86+ ...
87+
88+var
89+ MyBitmap: TBitmap
90+ ScreenDC: HDC;
91+begin
92+ MyBitmap := TBitmap.Create;
93+ ScreenDC := GetDC(0);
94+ MyBitmap.LoadFromDevice(ScreenDC);
95+ ReleaseDC(ScreenDC);
96+
97+ ...
98+```
99+
100+## Arbeiten mit TLazIntfImage
101+
102+### Beispiel: "Bild ausblenden"
103+
104+Ein Beispiel für 'fading' mit TLazIntfImage
105+
106+``` pascal
107+{ Dieser Code wurde dem $LazarusPath/examples/lazintfimage/fadein1.lpi Projekt entnommen. }
108+uses LCLType, // HBitmap type
109+ IntfGraphics, // TLazIntfImage type
110+ fpImage; // TFPColor type
111+...
112+ procedure TForm1.FadeIn(ABitMap: TBitMap);
113+ var
114+ SrcIntfImg, TempIntfImg: TLazIntfImage;
115+ ImgHandle,ImgMaskHandle: HBitmap;
116+ FadeStep: Integer;
117+ px, py: Integer;
118+ CurColor: TFPColor;
119+ TempBitmap: TBitmap;
120+ begin
121+ SrcIntfImg:=TLazIntfImage.Create(0,0);
122+ SrcIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);
123+ TempIntfImg:=TLazIntfImage.Create(0,0);
124+ TempIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);
125+ TempBitmap:=TBitmap.Create;
126+ for FadeStep:=1 to 32 do begin
127+ for py:=0 to SrcIntfImg.Height-1 do begin
128+ for px:=0 to SrcIntfImg.Width-1 do begin
129+ CurColor:=SrcIntfImg.Colors[px,py];
130+ CurColor.Red:=(CurColor.Red*FadeStep) shr 5;
131+ CurColor.Green:=(CurColor.Green*FadeStep) shr 5;
132+ CurColor.Blue:=(CurColor.Blue*FadeStep) shr 5;
133+ TempIntfImg.Colors[px,py]:=CurColor;
134+ end;
135+ end;
136+ TempIntfImg.CreateBitmaps(ImgHandle,ImgMaskHandle,false);
137+ TempBitmap.Handle:=ImgHandle;
138+ TempBitmap.MaskHandle:=ImgMaskHandle;
139+ Canvas.Draw(0,0,TempBitmap);
140+ end;
141+ SrcIntfImg.Free;
142+ TempIntfImg.Free;
143+ TempBitmap.Free;
144+ end;
145+```
146+
147+### Bildformat-spezifisches Beispiel
148+
149+Wie Sie wissen verwendet eine TBitmap für blau 8 Bit, für grün 8 Bit und für rot 8 Bit. Sie können direkt auf diese Bytes zugreifen, das ist um einiges schneller:
150+
151+``` pascal
152+uses LCLType, // HBitmap type
153+ IntfGraphics, // TLazIntfImage type
154+ fpImage; // TFPColor type
155+...
156+type
157+ TRGBTripleArray = array[0..32767] of TRGBTriple;
158+ PRGBTripleArray = ^TRGBTripleArray;
159+
160+procedure TForm1.FadeIn2(aBitMap: TBitMap);
161+ var
162+ IntfImg1, IntfImg2: TLazIntfImage;
163+ ImgHandle,ImgMaskHandle: HBitmap;
164+ FadeStep: Integer;
165+ px, py: Integer;
166+ CurColor: TFPColor;
167+ TempBitmap: TBitmap;
168+ Row1, Row2: PRGBTripleArray;
169+ begin
170+ IntfImg1:=TLazIntfImage.Create(0,0);
171+ IntfImg1.LoadFromBitmap(aBitmap.Handle,aBitmap.MaskHandle);
172+
173+ IntfImg2:=TLazIntfImage.Create(0,0);
174+ IntfImg2.LoadFromBitmap(aBitmap.Handle,aBitmap.MaskHandle);
175+
176+ TempBitmap:=TBitmap.Create;
177+
178+ //with Scanline-like
179+ for FadeStep:=1 to 32 do begin
180+ for py:=0 to IntfImg1.Height-1 do begin
181+ Row1 := IntfImg1.GetDataLineStart(py); //like Delphi TBitMap.ScanLine
182+ Row2 := IntfImg2.GetDataLineStart(py); //like Delphi TBitMap.ScanLine
183+ for px:=0 to IntfImg1.Width-1 do begin
184+ Row2^[px].rgbtRed:= (FadeStep * Row1^[px].rgbtRed) shr 5;
185+ Row2^[px].rgbtGreen := (FadeStep * Row1^[px].rgbtGreen) shr 5; // Fading
186+ Row2^[px].rgbtBlue := (FadeStep * Row1^[px].rgbtBlue) shr 5;
187+ end;
188+ end;
189+ IntfImg2.CreateBitmaps(ImgHandle,ImgMaskHandle,false);
190+
191+ TempBitmap.Handle:=ImgHandle;
192+ TempBitmap.MaskHandle:=ImgMaskHandle;
193+ Canvas.Draw(0,0,TempBitmap);
194+ end;
195+
196+ IntfImg1.Free;
197+ IntfImg2.Free;
198+ TempBitmap.Free;
199+ end;
200+```
201+
202+### Konvertierung zwischen TLazIntfImage und TBitmap
203+
204+Da Lazarus die Eigenschaft 'TBitmap.ScanLine' nicht kennt, ist die beste Art, auf die Pixels eines Bildes auf schnelle Weise lesend und schreibend zuzugreifen, indem Sie TLazIntfImage verwenden. Die TBitmap wird konvertiert in ein TLazIntfImage mittels TBitmap.CreateIntfImage(). Nach dem Modifizieren der Pixel kann es in eine TBitmap zurück konvertiert werden mittels TBitmap.LoadFromIntfImage(). Hier ist das Beispiel dazu - es erzeugt TLazIntfImage aus einer TBitmap, modifiziert sie und wandelt sie zurück in eine TBitmap.
205+
206+``` pascal
207+uses
208+ ...GraphType, IntfGraphics, LCLType, LCLProc, LCLIntf ...
209+
210+procedure TForm1.Button4Click(Sender: TObject);
211+var
212+ b: TBitmap;
213+ t: TLazIntfImage;
214+begin
215+ b := TBitmap.Create;
216+ try
217+ b.LoadFromFile('test.bmp');
218+ t := b.CreateIntfImage;
219+
220+ // Lies und/oder schreib in die Pixels
221+ t.Colors[10,20] := colGreen;
222+
223+ b.LoadFromIntfImage(t);
224+ finally
225+ t.Free;
226+ b.Free;
227+ end;
228+end;
229+```
230+
231+## Motion Graphics - Wie man Flimmern vermeidet
232+
233+Viele Programme zeichnen ihre Ausgabe als 2D Grafik in die Benutzeroberfläche. Wenn diese Grafiken schnell geändert werden müssen, werden Sie bald einem Problem begegnen: sich schnell ändernde Grafiken flimmern oft auf dem Bildschirm. Das passiert, weil der Zeichenprozess Zeit benötigt und der Benutzer deshalb manchmal ein vollständiges Bild, manchmal aber auch nur ein teilweise gezeichnetes Bild sieht.
234+
235+Aber wie kann ich das Flimmern vermeiden und das beste Zeichentempo erreichen? Natürlich können Sie mit Hardwarebeschleunigung unter Verwendung von OpenGL arbeiten, aber dieser Ansatz ist für kleine Programme oder alte Computer ziemlich ungeeignet. Dieses Tutorial konzentriert sich auf das Zeichnen in ein TCanvas. Wenn Sie Hilfe brauchen zu OpenGL, werfen Sie einen Blick auf das Beispiel, das mit Lazarus geliefert wird oder auf [[GLScene]]. Sie können auch A.J. Venter's Gamepack verwenden, das eine doppelt-gepufferte Zeichenfläche (double-buffered canvas) und eine Sprite-Komponente bereitstellt.
236+
237+Jetzt wollen wir die Optionen untersuchen, die wir für das Zeichnen auf eine Zeichenfläche (Canvas) haben:
238+
239+- Zeichnen in ein TImage
240+- Zeichnen im OnPaint-Ereignis des Formulars, der TPaintBox oder eines anderen Steuerelements
241+- Ein CustomControl erzeugen, das sich selbst zeichnet
242+- A.J. Venter's Gamepack benutzen
243+
244+### Zeichnen in ein TImage
245+
246+Ein TImage-Objekt besteht aus zwei Teilen: Ein TGraphic-Objekt, üblicherweise ein TBitmap, das das persistente Bild und die sichtbare Fläche enthält, die bei jedem OnPaint neu gezeichnet wird. Eine Änderung der Größe von TImage ändert **nicht** die Größe der Bitmap. Auf die Grafik (oder die Bitmap) kann man über Image1.Picture.Graphic (oder Image1.Picture.Bitmap) zugreifen. Die Zeichenfläche (Canvas) ist Image1.Picture.Bitmap.Canvas. Auf die Zeichenfläche mit dem sichtbaren Bereich eines TImage-Objekts kann man nur über Image1.Canvas zugreifen, während Image1.OnPaint aktiv ist.
247+
248+**Wichtig**: Verwenden Sie nie das OnPaint-Event von Image1, um auf die Graphik/das Bild von TImage zu zeichnen. Die Graphik von TImage wird zwischengespeichert, wenn Sie also darauf zeichnen, bleiben die Änderungen für immer dort. Außerdem wird, wenn Sie ständig neuzeichnen lassen, das Bild flickern. In diesem Fall können Sie einen anderen Ansatz versuchen. Zeichnen auf ein TImage ist langsamer als die anderen Verfahren.
249+
250+#### Ändern der Größe einer Bitmap in TImage
251+
252+Anmerkung: Tun Sie das nicht während OnPaint.
253+
254+``` pascal
255+with Image1.Picture.Bitmap do begin
256+ Width:=100;
257+ Height:=120;
258+end;
259+```
260+
261+Das selbe in einem Schritt:
262+
263+``` pascal
264+with Image1.Picture.Bitmap do begin
265+ SetSize(100, 120);
266+end;
267+```
268+
269+#### Zeichnen auf eine Bitmap in TImage
270+
271+Anmerkung: Tun Sie das nicht während OnPaint.
272+
273+``` pascal
274+with Image1.Picture.Bitmap.Canvas do begin
275+ // fill the entire bitmap with red
276+ Brush.Color := clRed;
277+ FillRect(0, 0, Width, Height);
278+end;
279+```
280+
281+Anmerkung: Innerhalb von Image1.OnPaint zeigt Image1.Canvas auf den flüchtigen sichtbaren Bereich. Außerhalb von Image1.OnPaint zeigt Image1.Canvas auf Image1.Picture.Bitmap.Canvas.
282+
283+Ein anderes Beispiel:
284+
285+``` pascal
286+procedure TForm1.BitBtn1Click(Sender: TObject);
287+var
288+ x, y: Integer;
289+begin
290+ // Zeichnet den Hintergrund
291+ MyImage.Canvas.Pen.Color := clWhite;
292+ MyImage.Canvas.Rectangle(0, 0, Image.Width, Image.Height);
293+
294+ // Zeichnet Rechtecke
295+ MyImage.Canvas.Pen.Color := clBlack;
296+ for x := 1 to 8 do
297+ for y := 1 to 8 do
298+ MyImage.Canvas.Rectangle(Round((x - 1) * Image.Width / 8), Round((y - 1) * Image.Height / 8),
299+ Round(x * Image.Width / 8), Round(y * Image.Height / 8));
300+end;
301+```
302+
303+#### Im flüchtigen sichtbaren Bereich einer TImage zeichnen
304+
305+Sie können nur während des OnPaint-Ereignisses in diesen Bereich zeichnen. OnPaint wird automatisch von der LCL aufgerufen, wenn der Bereich invalidiert wurde. Sie können den Bereich mit Image1.Invalidate manuell invalidieren. Dies ruft OnPaint nicht unmittelbar auf und Sie können Invalidate so oft Sie wollen aufrufen.
306+
307+``` pascal
308+procedure TForm.Image1Paint(Sender: TObject);
309+begin
310+ // paint a line
311+ Canvas.Pen.Color:=clRed;
312+ Canvas.Line(0,0,Width,Height);
313+end;
314+```
315+
316+### Zeichnen im OnPaint-Ereignis des Formulars, der TPaintBox oder eines anderen Steuerelements
317+
318+In diesem Fall müssen alle Zeichenoperationen im OnPaint-Ereignis des Formulars passieren. Die Elemente bleiben nicht im Puffer erhalten, wie bei TImage, und das Bildes muss mit jedem Aufruf des OnPaint-Ereignishandlers vollständig neu gezeichnet werden.
319+
320+### Ein CustomControl erzeugen, das sich selbst zeichnet
321+
322+Die Erzeugung eines CustomControl hat den Vorteil der Strukturierung ihres Codes und sie können das Bedienelement wieder verwenden. Dieser Ansatz ist sehr schnell, aber er kann dennoch Flimmern erzeugen, wenn Sie nicht erst in ein TBitMap und dann in das Canvas zeichnen. In diesem Fall besteht keine Notwendigkeit, das OnPaint Ereignis des Bedienelements zu verwenden.
323+
324+Hier ist ein Beispiel für ein CustomControl:
325+
326+``` pascal
327+uses
328+ Classes, SysUtils, Controls, Graphics, LCLType;
329+
330+type
331+ TMyDrawingControl = class(TCustomControl)
332+ public
333+ procedure EraseBackground(DC: HDC); override;
334+ procedure Paint; override;
335+ end;
336+
337+implementation
338+
339+procedure TMyDrawingControl.EraseBackground(DC: HDC);
340+begin
341+ // Entfernen Sie den Kommentar um das geerbte Löschen des Hintergrundes zu aktivieren
342+ //inherited EraseBackground(DC);
343+end;
344+
345+procedure TMyDrawingControl.Paint;
346+var
347+ x, y: Integer;
348+ Bitmap: TBitmap;
349+begin
350+ Bitmap := TBitmap.Create;
351+ try
352+ // Initialisiert die Größe der Bitmap
353+ Bitmap.Height := Height;
354+ Bitmap.Width := Width;
355+
356+ // Zeichnet den Hintergrund
357+ Bitmap.Canvas.Pen.Color := clWhite;
358+ Bitmap.Canvas.Rectangle(0, 0, Width, Height);
359+
360+ // Zeichnet Rechtecke
361+ Bitmap.Canvas.Pen.Color := clBlack;
362+ for x := 1 to 8 do
363+ for y := 1 to 8 do
364+ Bitmap.Canvas.Rectangle(Round((x - 1) * Width / 8), Round((y - 1) * Height / 8),
365+ Round(x * Width / 8), Round(y * Height / 8));
366+
367+ Canvas.Draw(0, 0, Bitmap);
368+ finally
369+ Bitmap.Free;
370+ end;
371+
372+ inherited Paint;
373+end;
374+```
375+
376+und wie wir es auf dem Formular erzeugen:
377+
378+``` pascal
379+procedure TMyForm.FormCreate(Sender: TObject);
380+begin
381+ MyDrawingControl:= TMyDrawingControl.Create(Self);
382+ MyDrawingControl.Height := 400;
383+ MyDrawingControl.Width := 500;
384+ MyDrawingControl.Top := 0;
385+ MyDrawingControl.Left := 0;
386+ MyDrawingControl.Parent := Self;
387+ MyDrawingControl.DoubleBuffered := True;
388+end;
389+```
390+
391+Es wird automatisch zerstört, weil wir Self als owner angeben.
392+
393+Das Setzen von Top und Left auf 0 ist nicht notwendig, da dies die Standardposition ist, aber es ist sinnvoll, um diese Position zu verdeutlichen.
394+
395+"MyDrawingControl.Parent := Self;" ist sehr wichtig und Sie werden Ihr Bedienelement nicht sehen, wenn Sie es nicht tun.
396+
397+"MyDrawingControl.DoubleBuffered := True;" wird benötigt, um das Flimmern unter Windows zu vermeiden. Es hat keinen Effekt unter gtk.
398+
399+### A.J. Venter's Gamepack benutzen
400+
401+Der Gamepack-Ansatz bedeutet, alles in ein doppelt gebuffertes Canvas zu zeichnen, dessen sichtbarer Bereich erst dann aktualisiert wird, wenn Sie fertig sind. Dies benötigt etwas mehr Code, aber es schafft die Fähigkeit, große, sich dynamisch ändernde Grafiken mit mehreren Elementen zu verarbeiten. Wenn Sie diese Technik verwenden möchten, sollten Sie sich das A.J. Venter's Gamepack ansehen, ein Set von Komponenten zur Entwicklung von Spielen mit Lazarus, das eine doppelt gebufferte Anzeigeflächen-Komponente sowie eine Sprite-Komponente bietet, entwickelt um sich gegenseitig ideal zu ergänzen.
402+
403+[Download: A.J. Venter's GamePack 1.0](http://www.4shared.com/file/tZj_Uh8Z/gamepack-10tar.html)
404+
405+Veraltete Links:
406+
407+- `svn co `[`svn://silentcoder.co.za/lazarus/gamepack`](svn://silentcoder.co.za/lazarus/gamepack)
408+- [A.J. Venter's gamepack homepage](http://outkastsolutions.co.za/outkast/index.php?option=com_openwiki&Itemid=&id=gamepack)
409+
410+## Bild Formate
411+
412+Hier ist eine Tabelle mit den entsprechenden Klassen für jedes Bildformat.
413+
414+| Format | Bild-Klasse | Unit |
415+|--------------------------------|-------------------------|----------|
416+| Cursor (cur) | TCursor | Graphics |
417+| Bitmap (bmp) | TBitmap | Graphics |
418+| Windows icon (ico) | TIcon | Graphics |
419+| Mac OS X icon (icns) | TicnsIcon | Graphics |
420+| Pixmap (xpm) | TPixmap | Graphics |
421+| Portable Network Graphic (png) | TPortableNetworkGraphic | Graphics |
422+| JPEG (jpg, jpeg) | TJpegImage | Graphics |
423+| PNM (pnm) | TPortableAnyMapGraphic | Graphics |
424+
425+Siehe auch die Liste der [[fcl-image|von der FCL (fcl-image) unterstützten Formate]].
426+
427+### Konvertieren von Formaten
428+
429+Manchmal wird es erforderlich, einen Grafiktyp in einen anderen zu konvertieren. Ein Weg dazu ist es, eine Grafik in ein Zwischenformat zu wandeln, und dieses in eine TBitmap zu konvertieren. Die meisten Formate können ein Bild aus einer TBitmap erzeugen.
430+
431+Konvertieren von Bitmap zu PNG und Abspeichern in einer Datei:
432+
433+``` pascal
434+procedure SaveToPng(const bmp: TBitmap; PngFileName: String);
435+var
436+ png : TPortableNetworkGraphic;
437+begin
438+ png := TPortableNetworkGraphic.Create;
439+ try
440+ png.Assign(bmp);
441+ png.SaveToFile(PngFileName);
442+ finally
443+ png.Free;
444+ end;
445+end;
446+```
447+
448+## Pixelformate
449+
450+### TColor
451+
452+Das interne Pixelformat für TColor in der LCL ist das XXBBGGRR Format, welches dem Windows-eigenen Format entspricht und im Gegensatz steht zu den meisten anderen Bibliotheken, die AARRGGBB verwenden. Der XX Teil gibt an, ob die Farbe eine festgelegte Farbe ist (XX = 00) oder ein Index zu einem Farbsystem. Für einen Alphakanal ist kein Platz reserviert.
453+
454+Zum Konvertieren von getrennten RGB-Kanälen zum Typ TColor nehmen Sie:
455+
456+``` pascal
457+RGBToColor(RedVal, GreenVal, BlueVal);
458+```
459+
460+Um aus einer TColor-Variablen jeden Kanal einzeln zu erhalten, benutzen Sie die Funktionen Red, Green, Blue:
461+
462+``` pascal
463+RedVal := Red(MyColor);
464+GreenVal := Green(MyColor);
465+BlueVal := Blue(MyColor);
466+```
467+
468+### TFPColor
469+
470+Der Typ TFPColor verwendet das AARRGGBB Format, das bei den meisten Bibliotheken üblich ist.
471+
472+## Arbeiten mit der Zeichenfläche TCanvas
473+
474+### Verwendung der Standardschriftart der GUI
475+
476+Das erreichen Sie mit diesem einfachen Code:
477+
478+``` pascal
479+SelectObject(Canvas.Handle, GetStockObject(DEFAULT_GUI_FONT));
480+```
481+
482+### Ausgabe eines in der Breite begrenzten Textes
483+
484+Nehmen Sie die Routine DrawText, zuerst mit DT_CALCRECT und dann ohne den Wert.
485+
486+``` pascal
487+// Berechne zuerst die Textbreite, dann zeiche ihn
488+TextBox := Rect(0, currentPos.Y, Width, High(Integer));
489+DrawText(ACanvas.Handle, PChar(Text), Length(Text),
490+ TextBox, DT_WORDBREAK or DT_INTERNAL or DT_CALCRECT);
491+
492+DrawText(ACanvas.Handle, PChar(Text), Length(Text),
493+ TextBox, DT_WORDBREAK or DT_INTERNAL);
494+```
495+
496+### Ausgabe eines Textes mit klaren Kanten (ohne Antialiasing)
497+
498+Einige Interfaces unterstützen dies mittels
499+
500+``` pascal
501+Canvas.Font.Quality := fqNonAntialiased;
502+```
503+
504+Einige Interfaces wie gtk2 unterstützen dies nicht und zeichnen immer mittels Antialiasing. Hier ist eine simple Prozedur um Text mit scharfen Kanten auch unter gtk2 darzustellen. Sie berücksichtigt nicht alle Fälle, aber zeigt die Grundidee:
505+
506+``` pascal
507+procedure PaintAliased(Canvas: TCanvas; x,y: integer; const TheText: string);
508+var
509+ w,h: integer;
510+ IntfImg: TLazIntfImage;
511+ Img: TBitmap;
512+ dy: Integer;
513+ dx: Integer;
514+ col: TFPColor;
515+ FontColor: TColor;
516+ c: TColor;
517+begin
518+ w:=0;
519+ h:=0;
520+ Canvas.GetTextSize(TheText,w,h);
521+ if (w<=0) or (h<=0) then exit;
522+ Img:=TBitmap.Create;
523+ IntfImg:=nil;
524+ try
525+ // paint text to a bitmap
526+ Img.Masked:=true;
527+ Img.SetSize(w,h);
528+ Img.Canvas.Brush.Style:=bsSolid;
529+ Img.Canvas.Brush.Color:=clWhite;
530+ Img.Canvas.FillRect(0,0,w,h);
531+ Img.Canvas.Font:=Canvas.Font;
532+ Img.Canvas.TextOut(0,0,TheText);
533+ // get memory image
534+ IntfImg:=Img.CreateIntfImage;
535+ // replace gray pixels
536+ FontColor:=ColorToRGB(Canvas.Font.Color);
537+ for dy:=0 to h-1 do begin
538+ for dx:=0 to w-1 do begin
539+ col:=IntfImg.Colors[dx,dy];
540+ c:=FPColorToTColor(col);
541+ if c<>FontColor then
542+ IntfImg.Colors[dx,dy]:=colTransparent;
543+ end;
544+ end;
545+ // create bitmap
546+ Img.LoadFromIntfImage(IntfImg);
547+ // paint
548+ Canvas.Draw(x,y,Img);
549+ finally
550+ IntfImg.Free;
551+ Img.Free;
552+ end;
553+end;
554+```
555+
556+## Zeichnen mit der Bibliothek fcl-image
557+
558+Sie können Bilder, die nicht am Bildschirm angezeigt werden sollen, auch ohne die LCL zeichnen, indem Sie die Bibliothek fcl-image einfach direkt ansprechen. Beispielsweise könnte ein Programm, das auf einem Webserver ohne X11 läuft, davon profitieren, nicht von einer visuellen Bibliothek abhängig zu sein. FPImage (alias fcl-image) ist eine sehr allgemeine Bibliothek für das Darstellen von Bildern und ist vollständig in Pascal geschrieben. Tatsächlich benutzt auch die LCL FPImage für alle Lade- und Speichervorgänge von Dateien und implementiert die Zeichenfunktionen durch Aufrufe an das jeweilige Interface (winapi, gtk, carbon, ...). Andererseits hat Fcl-image aber auch eigene Zeichenroutinen.
559+
560+Für weitere Informationen lesen Sie bitte den Artikel über [[fcl-image]].
561+
562+---
563+*From the Free Pascal wiki, page "Developing with Graphics/de", as it stood on 2020-02-13 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history