Difference between revisions of "Developing with Graphics/de"
m (→Image formats: translated) |
|||
Line 365: | Line 365: | ||
Sie erhalten weitere Informationen, Dokumentationen und Downloads auf der [http://outkastsolutions.co.za/outkast/index.php?option=com_openwiki&Itemid=&id=gamepack Homepage]. | Sie erhalten weitere Informationen, Dokumentationen und Downloads auf der [http://outkastsolutions.co.za/outkast/index.php?option=com_openwiki&Itemid=&id=gamepack Homepage]. | ||
− | == | + | == Bild Formate == |
− | + | Hier ist eine Tabelle mit den entsprechenden Klassen für jedes Bildformat. | |
{| border=2 width="100%" align="center" | {| border=2 width="100%" align="center" | ||
|- | |- | ||
! Format | ! Format | ||
− | ! | + | ! Bild-Klasse |
! Unit | ! Unit | ||
|- | |- | ||
Line 392: | Line 392: | ||
|} | |} | ||
− | + | Siehe auch die Liste der [[fcl-image#Image_formats|von der FCL (fcl-image) unterstützten Formate]]. | |
− | === | + | === Konvertieren von Formaten === |
− | |||
− | |||
− | |||
− | + | 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. | ||
+ | |||
+ | Konvertieren von Bitmap zu PNG und Abspeichern in einer Datei: | ||
<delphi>procedure SaveToPng(const bmp: TBitmap; PngFileName: String); | <delphi>procedure SaveToPng(const bmp: TBitmap; PngFileName: String); |
Revision as of 15:29, 20 February 2011
│
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) │
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.
Andere Grafikartikel
- BGRABitmap - Zeichnen von Formen und Bitmaps mit Transparenzinformationen, direkte Zugriff auf Pixels, etc.
- GLScene - Eine Portierung der visuellen OpenGL-Graphikbibliothek GLScene
- TAChart - Chartkomponente für Lazarus
- PascalMagick - ein einfach zu verwendendes API für die Kopplung mit ImageMagick, einer freien Multiplattform-Softwaresammlung um Bitmaps zu erzeugen, zu bearbeiten und zu entwerfen.
- PlotPanel - Eine Komponente zum Darstellen( Plotting / Charting) von animierten Graphen. Ähnlich wie TAChart.
- LazRGBGraphics - A package for fast in memory image processing and pixel manipulations (like scan line).
- Perlin Noise - Ein Artikel über die Verwendung von Perlin Noise in LCL Anwendungen.
- Double Gradient - Zeichnet 'doppelte Farbverläufe' und 'n-fache Farbverläufe' ganz einfach in Bitmaps.
- Gradient Filler - TGradientFiller is the best way to create custom n gradients in Lazarus.
Arbeiten mit TBitmap
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.
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. Um auf Bitmaps direkt zuzugreifen kann man das Lazarus-eigene TLazIntfImage einsetzen oder man nimmt dazu externe Bibliotheken, wie [BGRABitmap]], LazRGBGraphics und Graphics32.
Beachten Sie: Wenn Sie eine Bitmap erzeugen, müssen Sie deren Höhe und Breite immer angeben, ansonsten sind sie 0 und es wird nichts gezeichnet.
Direkter Zugriff auf Pixel
Mit Delphi kann man TBitmap.Scanline verwenden für einen schnellen Zugriff auf die Pixels. Weil diese Eigenschaft nicht portierbar ist, hat Lazarus eine andere Lösung. Nehmen Sie für diesen Fall TLazIntfImage und nicht TBitmap.Pixels, das *sehr* langsam ist.
Zeichnen von farbigen transparenten Bitmaps
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.
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).
<delphi>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; // Fehler beim Laden der 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; // Gibt belegte Ressourcen frei
end;</delphi>
Beachten Sie, dass die Speicheroperationen mit TMemoryStream ausgeführt werden. Sie sind notwendig, um das korrekte Laden des Bildes sicherzustellen.
Ein Bildschirmfoto erstellen
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):
<delphi>uses Graphics, LCLIntf, LCLType;
...
var
MyBitmap: TBitmap ScreenDC: HDC;
begin
MyBitmap := TBitmap.Create; ScreenDC := GetDC(0); MyBitmap.LoadFromDevice(ScreenDC); ReleaseDC(ScreenDC);
...</delphi>
Arbeiten mit TLazIntfImage
Beispiel: "Bild ausblenden"
Ein Beispiel für 'fading' mit TLazIntfImage
<delphi>{ Dieser Code wurde dem $LazarusPath/examples/lazintfimage/fadein1.lpi Projekt entnommen. } uses LCLType, // HBitmap type
IntfGraphics, // TLazIntfImage type fpImage; // TFPColor type
...
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.CreateBitmaps(ImgHandle,ImgMaskHandle,false); TempBitmap.Handle:=ImgHandle; TempBitmap.MaskHandle:=ImgMaskHandle; Canvas.Draw(0,0,TempBitmap); end; SrcIntfImg.Free; TempIntfImg.Free; TempBitmap.Free; end;</delphi>
Bildformat-spezifisches Beispiel
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:
<delphi>uses LCLType, // HBitmap type
IntfGraphics, // TLazIntfImage type fpImage; // TFPColor type
... type
TRGBTripleArray = array[0..32767] of TRGBTriple; PRGBTripleArray = ^TRGBTripleArray;
procedure TForm1.FadeIn2(aBitMap: TBitMap);
var IntfImg1, IntfImg2: TLazIntfImage; ImgHandle,ImgMaskHandle: HBitmap; FadeStep: Integer; px, py: Integer; CurColor: TFPColor; TempBitmap: TBitmap; Row1, Row2: PRGBTripleArray; begin IntfImg1:=TLazIntfImage.Create(0,0); IntfImg1.LoadFromBitmap(aBitmap.Handle,aBitmap.MaskHandle);
IntfImg2:=TLazIntfImage.Create(0,0); IntfImg2.LoadFromBitmap(aBitmap.Handle,aBitmap.MaskHandle);
TempBitmap:=TBitmap.Create; //with Scanline-like for FadeStep:=1 to 32 do begin for py:=0 to IntfImg1.Height-1 do begin Row1 := IntfImg1.GetDataLineStart(py); //like Delphi TBitMap.ScanLine Row2 := IntfImg2.GetDataLineStart(py); //like Delphi TBitMap.ScanLine for px:=0 to IntfImg1.Width-1 do begin Row2^[px].rgbtRed:= (FadeStep * Row1^[px].rgbtRed) shr 5; Row2^[px].rgbtGreen := (FadeStep * Row1^[px].rgbtGreen) shr 5; // Fading Row2^[px].rgbtBlue := (FadeStep * Row1^[px].rgbtBlue) shr 5; end; end; IntfImg2.CreateBitmaps(ImgHandle,ImgMaskHandle,false); TempBitmap.Handle:=ImgHandle; TempBitmap.MaskHandle:=ImgMaskHandle; Canvas.Draw(0,0,TempBitmap); end;
IntfImg1.Free; IntfImg2.Free; TempBitmap.Free; end;</delphi>
Konvertierung zwischen TLazIntfImage und TBitmap
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.
<delphi>uses
...GraphType, IntfGraphics, LCLType, LCLProc, LCLIntf ...
procedure TForm1.Button4Click(Sender: TObject); var
b: TBitmap; t: TLazIntfImage;
begin
b := TBitmap.Create; try b.LoadFromFile('test.bmp'); t := b.CreateIntfImage;
// Lies und/oder schreib in die Pixels t.Colors[10,20] := colGreen;
b.LoadFromIntfImage(t); finally t.Free; b.Free; end;
end;</delphi>
Motion Graphics - Wie man Flimmern vermeidet
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.
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.
Jetzt wollen wir die Optionen untersuchen, die wir für das Zeichnen auf eine Zeichenfläche (Canvas) haben:
- Zeichnen in ein TImage
- Zeichnen im OnPaint-Ereignis des Formulars, der TPaintBox oder eines anderen Steuerelements
- Ein CustomControl erzeugen, das sich selbst zeichnet
- A.J. Venter's Gamepack benutzen
Zeichnen in ein TImage
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.
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.
Ändern der Größe einer Bitmap in TImage
Anmerkung: Tun Sie das nicht während OnPaint.
<delphi>with Image1.Picture.Bitmap do begin
Width:=100; Height:=120;
end;</delphi>
Zeichnen auf eine Bitmap in TImage
Anmerkung: Tun Sie das nicht während OnPaint.
<delphi>with Image1.Picture.Bitmap.Canvas do begin
// fill the entire bitmap with red Brush.Color := clRed; FillRect(0, 0, Width, Height);
end;</delphi>
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.
Ein anderes Beispiel:
<delphi>procedure TForm1.BitBtn1Click(Sender: TObject); var
x, y: Integer;
begin
// Zeichnet den Hintergrund MyImage.Canvas.Pen.Color := clWhite; MyImage.Canvas.Rectangle(0, 0, Image.Width, Image.Height); // Zeichnet Rechtecke 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;</delphi>
Im flüchtigen sichtbaren Bereich einer TImage zeichnen
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.
<delphi>procedure TForm.Image1Paint(Sender: TObject); begin
// paint a line Canvas.Pen.Color:=clRed; Canvas.Line(0,0,Width,Height);
end;</delphi>
Zeichnen im OnPaint-Ereignis des Formulars, der TPaintBox oder eines anderen Steuerelements
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.
Ein CustomControl erzeugen, das sich selbst zeichnet
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.
Hier ist ein Beispiel für ein CustomControl:
<delphi>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
// Entfernen Sie den Kommentar um das geerbte Löschen des Hintergrundes zu aktivieren //inherited EraseBackground(DC);
end;
procedure TMyDrawingControl.Paint; var
x, y: Integer; Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create; try // Initialisiert die Größe der Bitmap Bitmap.Height := Height; Bitmap.Width := Width;
// Zeichnet den Hintergrund Bitmap.Canvas.Pen.Color := clWhite; Bitmap.Canvas.Rectangle(0, 0, Width, Height); // Zeichnet Rechtecke 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;</delphi>
und wie wir es auf dem Formular erzeugen: <delphi>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;</delphi>
Es wird automatisch zerstört, weil wir Self als owner angeben.
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.
"MyDrawingControl.Parent := Self;" ist sehr wichtig und Sie werden Ihr Bedienelement nicht sehen, wenn Sie es nicht tun.
"MyDrawingControl.DoubleBuffered := True;" wird benötigt, um das Flimmern unter Windows zu vermeiden. Es hat keinen Effekt unter gtk.
A.J. Venter's Gamepack benutzen
Der Gamepack-Vorstoß 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. Sie können Gamepack mittels Subversion erhalten:
svn co svn://silentcoder.co.za/lazarus/gamepack
Sie erhalten weitere Informationen, Dokumentationen und Downloads auf der Homepage.
Bild Formate
Hier ist eine Tabelle mit den entsprechenden Klassen für jedes Bildformat.
Format | Bild-Klasse | Unit |
---|---|---|
Cursor (cur) | TCursor | Graphics |
Bitmap (bmp) | TBitmap | Graphics |
Windows icon (ico) | TIcon | Graphics |
Mac OS X icon (icns) | TicnsIcon | Graphics |
Pixmap (xpm) | TPixmap | Graphics |
Portable Network Graphic (png) | TPortableNetworkGraphic | Graphics |
JPEG (jpg, jpeg) | TJpegImage | Graphics |
PNM (pnm) | TPortableAnyMapGraphic | Graphics |
Siehe auch die Liste der von der FCL (fcl-image) unterstützten Formate.
Konvertieren von Formaten
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.
Konvertieren von Bitmap zu PNG und Abspeichern in einer Datei:
<delphi>procedure SaveToPng(const bmp: TBitmap; PngFileName: String); var
png : TPortableNetworkGraphic;
begin
png := TPortableNetworkGraphic.Create; try png.Assign(bmp); png.SaveToFile(PngFileName); finally png.Free; end;
end;</delphi>
Pixel Formats
TColor
The internal pixel format for TColor in the LCL is the XXBBGGRR format, which matches the native Windows format and is opposite to most other libraries, which use AARRGGBB. The XX part is used to identify if the color is a fixed color, which case XX should be 00 or if it is an index to a system color. There is no space reserved for an alpha channel.
To convert from separate RGB channels to TColor use:
<delphi>RGBToColor(RedVal, GreenVal, BlueVal);</delphi>
To get each channel of a TColor variable use the Red, Green and Blue functions:
<delphi>RedVal := Red(MyColor); GreenVal := Green(MyColor); BlueVal := Blue(MyColor);</delphi>
TFPColor
TFPColor uses the AARRGGBB format common to most libraries.
Working with TCanvas
Using the default GUI font
This can be done with this simple code:
<delphi>SelectObject(Canvas.Handle, GetStockObject(DEFAULT_GUI_FONT));</delphi>
Drawing a text limited on the width
Use the DrawText routine, first with DT_CALCRECT and then without it.
<delphi>// First calculate the text size then draw it TextBox := Rect(0, currentPos.Y, Width, High(Integer)); DrawText(ACanvas.Handle, PChar(Text), Length(Text),
TextBox, DT_WORDBREAK or DT_INTERNAL or DT_CALCRECT);
DrawText(ACanvas.Handle, PChar(Text), Length(Text),
TextBox, DT_WORDBREAK or DT_INTERNAL);</delphi>
Drawing text with sharp edges (non antialiased)
Some widgetsets support this via
<Delphi>Canvas.Font.Quality := fqNonAntialiased;</Delphi>
Some widgetsets like the gtk2 do not support this and always paint antialiased. Here is a simple procedure to draw text with sharp edges under gtk2. It does not consider all cases, but it should give an idea:
<Delphi>procedure PaintAliased(Canvas: TCanvas; x,y: integer; const TheText: string); var
w,h: integer; IntfImg: TLazIntfImage; Img: TBitmap; dy: Integer; dx: Integer; col: TFPColor; FontColor: TColor; c: TColor;
begin
w:=0; h:=0; Canvas.GetTextSize(TheText,w,h); if (w<=0) or (h<=0) then exit; Img:=TBitmap.Create; IntfImg:=nil; try // paint text to a bitmap Img.Masked:=true; Img.SetSize(w,h); Img.Canvas.Brush.Style:=bsSolid; Img.Canvas.Brush.Color:=clWhite; Img.Canvas.FillRect(0,0,w,h); Img.Canvas.Font:=Canvas.Font; Img.Canvas.TextOut(0,0,TheText); // get memory image IntfImg:=Img.CreateIntfImage; // replace gray pixels FontColor:=ColorToRGB(Canvas.Font.Color); for dy:=0 to h-1 do begin for dx:=0 to w-1 do begin col:=IntfImg.Colors[dx,dy]; c:=FPColorToTColor(col); if c<>FontColor then IntfImg.Colors[dx,dy]:=colTransparent; end; end; // create bitmap Img.LoadFromIntfImage(IntfImg); // paint Canvas.Draw(x,y,Img); finally IntfImg.Free; Img.Free; end;
end;</Delphi>
Drawing with fcl-image
You can draw images which won't be displayed in the screen without the LCL, by just using fcl-image directly. For example a program running on a webserver without X11 could benefit from not having a visual library as a dependency. FPImage (alias fcl-image) is a very generic image and drawing library written completely in pascal. In fact the LCL uses FPImage too for all the loading and saving from/to files and implements the drawing function through calls to the widgetset (winapi, gtk, carbon, ...). Fcl-image on the other hand also has drawing routines.
For more information, please read the article about fcl-image.