Difference between revisions of "Developing with Graphics/de"
Line 101: | Line 101: | ||
===Drawing color transparent bitmaps=== | ===Drawing color transparent 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 | + | 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 Farbe wählen um den transparenten Bereich zu representieren. Dies ist ein üblicher Trick, der bei Win32 Anwendungen verwendet wird. |
Das folgende Beispiel lädt eine Bitmap aus einer Windows Ressource, wählt eine Farbe für die Transparenz (clFuchsia) und zeichnet es auf den Canvas. | Das folgende Beispiel lädt eine Bitmap aus einer Windows Ressource, wählt eine Farbe für die Transparenz (clFuchsia) und zeichnet es auf den Canvas. |
Revision as of 21:08, 28 March 2006
│
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 wird der Anfang von Tutorials sein bezüglich der Manipulation von Bitmaps und anderen Grafiken. Da ich kein Grafikprogrammierer bin, lade ich alle ein ihr Wisen zu teilen! Fügen sie einfach einen Link zum nächsten Abschnitt hinzu, fügen eine Seite hinzu und erzeugen ihren eigenen WiKi Artikel.
Auf dieser Seite werden einige allgemeine Informationen geboten.
Andere Grafik Artikel
- GLScene - Eine Portierung der visual OpenGL graphics Library GLScene
- TAChart - Chartkomponente für Lazarus
- PlotPanel - Ähnlich wie TAChart
- PascalMagick - ein einfach zu verwendentes API für die Kopplung mit ImageMagick, einer freien multiplattform Softwaresammlung um Bitmaps zu erzeugen, zu bearbeiten und zu entwerfen.
Arbeiten mit TBitmap
Das erste woran sie denken sollten ist, daß Lazarus plattformunabhängig sein soll. Daher kommen alle Methoden, welche die Windows API Funktionalität nutzen, nicht in Frage. Daher wird eine Methode wie ScanLine nicht von Lazarus unterstützt, weil sie gedacht ist für Geräte-unabhängige Bitmaps und Funktionen von GDI32.dll verwendet.
Geben sie acht, daß wenn sie nicht die Breite und Höhe ihrer TBitmap spezifizieren, sie die Standardmaße haben wird, welche ziemlich klein sind.
A fading example
Sagen wir sie wollen ein Fading picture erstellen. In Delphi können sie etwas wie dieses tun:
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; // oder 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;
Diese Funktion in Lazarus könnte so implementiert werden:
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;
Der Lazarus Code auf dieser Seite wurde dem $LazarusPath/examples/lazintfimage/fadein1.lpi Projekt entnommen. Wenn sie einen fliegenden Start mit der Grafikprogrammierung wollen, dann werfen sie einen näheren Blick auf dieses Beispiel.
Drawing color transparent 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 Farbe wählen um den transparenten Bereich zu representieren. Dies ist ein üblicher Trick, der bei Win32 Anwendungen verwendet wird.
Das folgende Beispiel lädt eine Bitmap aus einer Windows Ressource, wählt eine Farbe für die Transparenz (clFuchsia) und zeichnet es auf den 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; // 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;
Beachten sie, daß die Speicheroperationen ausgeführt werden mit TMemoryStream. Sie sind notwendig, um das korrekte Laden des Bildes sicherzustellen.
Motion Graphics - Wie man flimmern vermeidet
Viele Programme zeichnen ihre Ausgabe als 2D Grafik in die GUI. 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 wenn der Benutzer manchmal das ganze Bild sieht und manchmal wenn es nur teilweise gezeichnet ist. Das geschieht weil der Zeichenprozess Zeit benötigt.
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 ziemlich schwer für kleine Programme oder alte Computer. Dieses Tutorial will sich auf das Zeichnen in ein TCanvas konzentrieren. Wenn sie Hilfe brauchen zu OpenGL, werfen sie einen Blick auf das Beispiel, das mit Lazarus geliefert wird oder GLScene. Sie können auch A.J. Venter's gamepack verwenden, welches einen double-buffered canvas und eine sprite Komponente bereitstellt.
Jetzt wollen wir die Optionen untersuchen, die wir für das Zeichnen in ein Canvas haben:
- Zeichnen in ein TImage
- Draw on the OnPaint event of the form, a TPaintBox or another control
- Create a custom control which draws itself
- Using A.J. Venter's gamepack
Zeichnen in ein TImage
Benutzen sie niemals das OnPaint Ereignis, um in ein TImage zu zeichnen. Ein TImage ist gebuffert so das Sie nur ein mal darauf Zeichnen müssen und die Änderung bleibt. Wenn sie es ständig neuzeichnen wird auch das TImage flackern. In diesem Fall können sie die anderen Optionen versuchen. Zeichnen in ein TImage wird als langsamer betrachtet als die anderen Ansätze.
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 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;
Draw on the OnPaint event
In this case all the drawing has to be done on the OnPaint event of the form. It doesn't remain on the buffer, like on the TImage.
Create a custom control which draws itself
Die Erzeugung eines custom control hat den Vorteil der Strukturing ihres Codes und sie können das Bedienelement wiederverwenden. Dieser Ansatz ist sehr schnell, aber er kann dennoch Flimmern erzeugen if you don't draw to a TBitmap first and then draw to the canvas. In diesem Fall besteht keine Notwendigkeit das OnPaint Ereignis des Bedienelements zu verwenden.
Hier ist ein Beispiel custom control:
type
TMyDrawingControl = class(TCustomControl)
public
procedure Paint; override;
end;
implementation
procedure TMyDrawingControl.Paint;
var
x, y: Integer;
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
// Initialisiert die Bitmap Größe
Bitmap.Height := Height;
Bitmap.Width := Width;
// Zeichnet den Hintergrund
Bitmap.Canvas.Pen.Color := clWhite;
Bitmap.Canvas.Rectangle(0, 0, Width, Height);
// Zeichnet 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;
und wie wir es auf dem Formular erzeugen:
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;
nur nicht vergessen es zu löschen:
procedure TMyForm.FormDestroy(Sender: TObject);
begin
MyDrawingControl.Free;
end;
Das Setzen von Top und Left auf null ist nicht notwendig, seit dies die Standardposition ist, but is done so to reinforce where the control will be put.
"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.
Using A.J. Venter's gamepack
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. Sie können gamepack erhalten mittels subversion:
svn co svn://silentcoder.co.za/lazarus/gamepack