BGRABitmap tutorial 13/de
│ Deutsch (de) │ English (en) │
Home | Tutorial 1 | Tutorial 2 | Tutorial 3 | Tutorial 4 | Tutorial 5 | Tutorial 6 | Tutorial 7 | Tutorial 8 | Tutorial 9 | Tutorial 10 | Tutorial 11 | Tutorial 12 | Tutorial 13 | Tutorial 14 | Tutorial 15 | Tutorial 16 | Edit
Dieses Tutorial beschreibt das Koordinatensystem von BGRABitmap.
Pixelkoordinaten
Die Routinen der Standardleinwand verwenden ganzzahlige Koordinaten. Dies ist ebenfalls so bei der Eigenschaft 'CanvasBGRA', welche die Funktionen der Standardleinwand emuliert, allerdings zusätzlich mit Antialiasing (AntialiasingMode), Alphablending (Eigenschaft 'Opacity' von Pen, Brush und Font) und Gammakorrektur.
Wenn wir uns nur auf die Integerkoordinaten beschränken ohne Antialiasing, dann bestimmen die Koordinaten eine Pixelposition, d.h. ein Quadrat. Wenn wir also eine Linie zeichnen von (0,0) nach (5,5), dann ist das oberste, linke Pixel auch das erste gezeichnete Pixel. Bei der Standardleinwand wird das letzte Pixel nicht gezeichnet, die Linie endet also bei (4,4).
Wenn wir eine Ellipse zeichnen, legt das umgebende Rechteck die Pixel fest, die wir zur Darstellung der Ellipse verwenden. Auch hier gilt, dass bei der Standardleinwand die unteren rechten Koordinaten von der Zeichnung ausgeschlossen sind, somit sind beim Füllen des Rechtecks (0,0)-(5,5) in Wirklichkeit nur die Pixel mit den Koordinaten von 0 bis 4 betroffen.
Fließkommakoordinaten
Wenn wir jetzt mit dezimalen Werte arbeiten, geben die Koordinaten eine Position an, die irgendwo auf den Pixeln liegen kann. Der Wert Breite des Stiftes bedeutet eine wirkliche Distanz, nicht nur eine Anzahl von Pixeln. Was stellt (0.0,0.0) also dar?
Fließkommakoordinaten ab der oberen, linken Ecke
Es könnte beispielsweise die Distanz von der oberen, linken Ecke sein (-dies ist bei BGRABitmap aber nicht der Fall -). Dann würde diese Koordinate die obere, linke Ecke des ersten Pixels sein. Aber wenn wir das so betrachten, ist das Verhalten zwischen ganzzahligen und Fließkommakoordinaten leicht unterschiedlich. Genau, stellen Sie sich vor, wir zeichneten eine waagrechte Linie auf den Pixeln (0,1) bis (4,1). In Pixelkoordinaten wäre das die Linie (0,1)-(5,1) und die Breite wäre 1 Pixel. Nun wollen wir aber dieses Segment mit Fließkommakoordinaten definieren. Die linke Seite wäre bei 0.0, die rechte bei 5.0, das passt. Die obere Seite wäre bei 1.0 und die untere bei 2.0. Hier liegt das Problem. Die Mitte der Linie liegt bei der vertikalen Koordinate 1.5. Um also diese Linie zu zeichnen, sollten wir die Koordinaten (0.0,1.5)-(5.0,1.5) angeben.
Tatsächlich würde jede Linie mit der Breite 1 Pixel bei ganzzahligen Koordinaten zwischen den Pixeln gezeichnet, und dies würde mit Antialiasing zu verschwommenen Linien führen. Was bei horizontalen Koordinaten in Ordnung zu sein schien, ist in Wirklichkeit eine Illusion, denn wenn die Linie abgerundete Enden hat, sind die korrekten Koordinaten (0.5,1.5)-(4.5,1.5). Wenn wir das Problem des letzten Pixels außer Acht lassen, sehen wir, dass diese Koordinaten einfach um 0.5 größer sind.
Fließkommakoordinaten ab der Pixelmitte
Die Koordinaten könnten auch der Abstand von der Mitte des oberen, linken Pixels sein. Mit anderen Worten sind ganzzahlige Werte in der Mitte der Pixel. Dies ist bei den Funktionen von BGRABitmap der Fall. Nimmt man diese Koordinaten, dann ergibt die Linie, die die Pixel (0,1) bis (4,1) füllt, einfach (0.0,1.0)-(4.0,1.0).
Dies ist aus mathematischer Sicht seltsam, aber sehr praktisch, weil Sie ganzzahlige Koordinaten verwenden können, um normale, 1 Pixel breite Linien zu zeichnen. Auf diese Weise gibt es allerdings einen leichten Unterschied im Aufruf zwischen den Funktionen von CanvasBGRA und normalen Fließkommafunktionen von BGRABitmap.
Erzeugen Sie ein neues Projekt
Erzeugen Sie ein neues Projekt und fügen Sie eine Referenz auf BGRABitmap hinzu, genau so wie im ersten Tutorial.
Canvas und BGRACanvas
Versuchen wir zu zeigen, was auf Pixelebene passiert.
Zuerst verwenden wir die Standardleinwand (Canvas):
procedure TForm1.FormPaint(Sender: TObject);
var image: TBGRABitmap;
begin
image := TBGRABitmap.Create(10,10);
with image.Canvas do
begin
//einfach weiß
brush.color := clWhite;
FillRect(0,0,image.width,image.height);
//blaue Ellipse mit schwarzem Rand
brush.style := bsClear;
pen.color := clBlack;
Ellipse(0,0,9,9);
end;
/strecke das Bild, damit wir die Pixel sehen können
BGRAReplace(image,image.Resample(image.Width*10,image.Height*10,rmSimpleStretch));
image.Draw(Canvas,0,0,True);
image.free;
end;
Die Resample-Option 'rmSimpleStretch' bewahrt uns vor Interpolationsfiltern.
Sie sollten dies erhalten:
Die Pixel der Koordinate 9 sind nicht gefüllt (wie bereits oben unter Umgebungsrechteck erklärt). Jetzt zeichnen wir auf die BGRACanvas. Ändern Sie einfach die 'with'-Zeile:
with image.CanvasBGRA do
Jetzt sollten Sie dies erhalten:
Das Ergebnis ist recht ähnlich, abgesehen vom Antialiasing.
Tiefere Überlegungen
Angenommen, wir wollten eine gefüllte, antialiasierte Ellipse zeichnen, die genau in eine 9x9 Bitmap passt. Wir könnten diesen Code versuchen:
procedure TForm1.FormPaint(Sender: TObject);
var image: TBGRABitmap;
begin
image := TBGRABitmap.Create(9,9,BGRAWhite);
image.FillEllipseAntialias(4,4, 4,4, BGRABlack);
BGRAReplace(image,image.Resample(image.Width*10,image.Height*10,rmSimpleStretch));
image.Draw(Canvas,0,0,True);
image.free;
end;
Wir erhalten:
Wie Sie sehen, ist der Rand nicht vollständig gefüllt. Die Ellipse ist kleiner als erwartet. Tatsächlich liegt der Mittelpunkt der Ellipse bei (4,4) und der linke Rand bei (0,4). Aber aufgepasst, das ist die Mitte des Pixels. Wenn wir also wollen, dass die Ellipse bis zum Rand des Pixels reicht, müssen wir den Radius um 0.5 vergrößern:
image.FillEllipseAntialias(4,4, 4.5,4.5, BGRABlack);
Gefüllte Formen mit Canvas
Beachten Sie, dass mit der Standardleinwand das Ergebnis sehr überraschend ausfällt. Angenommen, wir wollten das selbe wie oben machen. Wir könnten folgendes versuchen:
brush.color := clWhite;
FillRect(0,0,image.width,image.height);
brush.color := clBlue;
pen.style := psClear;
Ellipse(0,0,9,9);
Wir erhalten dies:
In diesem Fall wurde noch ein weiteres Pixel abgezogen. Die Ellipse ist 8 Pixel breit, wohingegen das bereitgestellte Rechteck 9 Pixel breit ist.
Voriges Tutorial (Textfunktionen) | Nächstes Tutorial (Canvas2D)