GDI+
1. Was ist überhaupt das "GDI"?
Das GDI ist seit der ersten Version von Windows die Schnittstelle für Grafikausgaben aller Art. Seit Windows XP hat Microsoft eine neue, überarbeitete Version in Windows eingeführt. Beim GDI+ sind verschiedene neue Funktionen hinzugekommen, das Problem dabei ist jedoch, dass nur bei Windows XP Standardmäßig eine Unterstützung dafür vorhanden ist. Allerdings läßt sich alles nach inklusive Windows 98 Aufrüsten (Siehe Link am Ende)
Folgende neue Funktionen sind hinzugekommen:
- Transformationen:
- Rotierung
- Skalierung
- Verschiebung
- Grafikausgabe:
- Cardinal SPlines (Kurven, die beliebig viele Punkte berühren)
- Unterstützung von JPEG, TIFF, PNG, ...
- Textausgabe:
- Zentrierter, Rechtsbündiger Text
- Tab-Stopps
- ...
2. Möglichkeiten
Es gibt mehrere Möglichkeiten das neue GDI zu nutzen. Entweder man nutzt eine Headerdatei,
wie ich sie z.B.
hier hochgeladen habe. Man kann auch Komponenten nutzen, wobei man sich dann in der Regel nicht mehr um die Header zu kümmern braucht. (
hier habe meine vorgestellt). Ich werde hier nur auf die Verwendung der Header eingehen, dabei sollte es auch möglich sein, andere Übersetzungen zu nutzen.
3. Grundgerüst
Das Grundgerüst jeder GDI+ Zeichenoperation sieht folgendermaßen aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| var graphic: GGraphics; begin graphic := GGraphics.Create(DeviceContext); try finally graphic.free; end; end; |
Alternativ kann man natürlich auch auf die Variable verzichten indem man das ganze in einen with-try-finally Block einbaut.
4. Zusatzmethoden
Ich nutze folgende Zusatzmethoden, die einige Tipparbeit ersparen können (auch wenn hier nicht alle gebraucht werden):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| function RGBToColor(r,g,b: byte): color; begin result.New(r,g,b); end;
function ARGBToColor(a, r,g,b: byte): color; overload; begin result.New(a,r,g,b); end;
function ARGBToColor(argb: cardinal): color; overload; begin result.New(argb); end;
function MakePoint(x,y: integer): point; begin result.New(x,y); end;
function MakePointF(x,y: single): pointf; begin result.New(x,y); end; |
5. Zeichnen von Bildern und Transformationen
Die einfachste Bild-Zeichen-Methode sieht folgendermaßen aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| var graphic: GGraphics; img: Image; begin graphic := GGraphics.Create(Canvas.Handle); try img := Image.Create('knorkwarz1.bmp'); try graphic.DrawImage(img, 10, 10); finally img.Free; end; finally graphic.free; end; end; |
Hier wird zuerst das Bild geöffnet, an Position 10,10 gezeichnet und wieder freigegeben.
Ein Hinweis zu FromFile: Die Funktion ist eine Klassenmethode, also muss man Image.FromFile('...') schreiben. Die Rückgabe ist zwar eine
neue Instanz vom Typ Image, die man auch wieder Ordungsgemäß freigeben sollte. Richtig ist also img := image.FromFile('dateiname')
Jetzt wollen wir unser Bild noch Drehen, danach verschieben und zuletzt wieder in der Ursprünglichen Form zeichnen.
Delphi-Quelltext
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:
| var graphic: GGraphics; img: Image; begin graphic := GGraphics.Create(Canvas.Handle); try img := Image.Create('Bild.bmp'); try graphic.RotateTransform(20); graphic.DrawImage(img, 10, 10); graphic.TranslateTransform(20, 20); graphic.DrawImage(img, 10, 10); graphic.ResetTransform; finally img.Free; end; finally graphic.free; end; end; |
Je nach Größe des Bildes kann es sein, dass sich die Bilder überlappen. Am besten ist es, jede Zeile einmal auszuklammern und die Werte zu ändern, damit man sieht, was passiert.
Man sieht, dass Transformationen nicht nur eine Zeichenoperation erhalten bleiben, sondern so lange, bis entweder mit SetTransform(matrix) eine Transformationsmatrix geladen wird, oder mit Resettransform wieder der Ursprüngliche Zustand hergestellt wird.
6. Textausgabe
Wenn man zum Text kommt, wird das Ganze schon etwas umständlicher.
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:
| procedure TForm1.Button2Click(Sender: TObject); var graphic: GGraphics; brush: SolidBrush; font: GFont; col: GpColor; pt: Gppointf; begin graphic := GGraphics.Create(Canvas.Handle); try col.new(255,255,255); graphic.Clear(col); col.new(255,0,0); brush := SolidBrush.Create(col); try font := GFont.Create('times', 30); try pt.new(10,10); graphic.DrawString('Test', -1, font, pt, brush); finally font.free; end; finally brush.Free; end; finally graphic.free; end; end; |
Bei GFont.Create(...) lassen sich auch mehr als 2 Parameter angeben. Beispiel:
font := GFont.Create('times', 10, FontStyleBold or FontStyleUnderline, UnitMillimeter);
für fetten, unterstrichenen, 10 Millimeter hohen Text.
Für FontStyle... lassen sich folgende Werte eintragen (Die auch mit or verknüpft werden können):
Quelltext
1: 2: 3: 4: 5: 6:
| FontStyleRegular ......Normal (Standard) FontStyleBold .........Fett FontStyleItalic .......Kursiv FontStyleBoldItalic ...Fett + Kursiv (FontStyleBold or FontStyleItlic) FontStyleUnderline ....Unterstrichen FontStyleStrikeout ....Durchgestrichen |
Für Unit... sind folgende Werte interessant:
Quelltext
1: 2: 3: 4: 5:
| UnitPixel .............Jede Einheit ist ein Pixel UnitPoint .............Jede Einheit ist ein Punkt eines Druckers oder 1/72 Inch UnitInch ..............Jede Einheit ist ein Inch UnitDocument ..........Jede Einheit ist 1 / 300 Inch UnitMillimeter ........Jede Einheit ist ein Millimeter |
Selbstverständlich sind Transformationen auch für Text.
7. Cardinal SPlines und Linien
Wenn man sich die Deklaration von DrawCurve ansieht,
Delphi-Quelltext
1:
| function Graphics.DrawCurve(const pen: Pen; points: PointF; count: integer): Status; |
Fällt auf dass weder ein Array noch ein Pointer vorhanden ist. Allerdings funktioniert es wenn man das erste Element eines Arrays übergibt.
Hier jetzt noch ein Beispiel zur Verwendung:
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:
| var graphic: GGraphics; pen: GPen; col: gpcolor; i: integer; pts: array[0..3] of point; begin graphic := GGraphics.Create(Canvas.Handle); try col.new(255,255,255); graphic.Clear(col); pen := GPen.Create(255, 0, 0, 1.5); Graphic.TranslateTransform(100,100); pts[0] := MakePoint(0,0); pts[1] := MakePoint(40,70); pts[2] := MakePoint(150,90); pts[3] := MakePoint(200,30); for i := 0 to 8 do graphic.DrawCurve(pen, pts[0], 4, i/2); graphic.ResetTransform; Graphic.TranslateTransform(0,30); graphic.DrawLine(pen, 10, 250, 400,300); graphic.DrawRectangle(pen, 40,60,310,170); graphic.DrawEllipse(pen, 370,0,100,100); finally graphic.free; end; end; |
Die Funktionen für das Füllen von Rechtecken und Ellipsen heißen FillRectangle und FillEllipse.
So, ich habe jetzt genug für Heute, morgen mache ich vielleicht den 2. Teil. Dort werden dann mit Muster gefüllte Polygone, normale Polygone, Bézierkurven, Kuchen und weitere Funktionen beim Bilder-Zeichnen drankommen.
http://www.microsoft.com/downloads/details.aspx?...
Moderiert von tommie-lie: Link korrigiert
//Edit: Den einen oder anderen inhaltlichen Fehler korrigiert und den Headerlink aktualisiert
//Edit2: try-finally-Blocks eingebaut