Difference between revisions of "BGRABitmap tutorial 13/de"

From Lazarus wiki
Jump to navigationJump to search
m (partially translated)
 
m (translated)
Line 19: Line 19:
 
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?  
 
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?  
  
==== Obere, linke Distanz bei Fließkommakoordinaten ====
+
==== Fließkommakoordinaten ab der oberen, linken Ecke ====
  
It can be for example the distance from the top-left corner (this is not the case of BGRABitmap). In this case, this coordinate would be the upper-left corner of the first pixel. But if we do so, the behavior is slightely different between integer coordinates and floating point coordinates. Indeed, imagine we draw an horizontal segment on pixels (0,1) to (4,1). In pixel coordinates it would be the line (0,1)-(5,1) and the width would be 1 pixel. Now if we want to define this segment with floating point coordinates. The left side would be at 0.0, the right at 5.0, that's ok. The top side would be at 1.0 and the bottom at 2.0. Here is the problem. The center of the line is at a vertical coordinate of 1.5. So to draw this line, we should supply coordinates (0.0,1.5)-(5.0,1.5).  
+
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.  
  
 
[[Image:BGRATutorial13b.png]]
 
[[Image:BGRATutorial13b.png]]
  
In fact every 1-pixel wide line with integer coordinates would be drawn between pixels, and with antialiasing, this leads to blurred lines. What appeared to be ok with horizontal coordinates is in fact an illusion, because if the line has caps, the correct coordinates are (0.5,1.5)-(4.5,1.5). If we ignore the last pixel issue, we see that these coordinates are simply 0.5 greater.
+
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.
  
==== Pixel-center floating point coordinates ====
+
==== Fließkommakoordinaten ab der Pixelmitte ====
  
The coordinates can be the distance from the center of the top-left pixel. In other words, integer values are at the center of the pixels.This is the case of BGRABitmap functions. Using these coordinates, the line that fills pixels (0,1) to (4,1) is simply (0.0,1.0)-(4.0,1.0).
+
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).
  
 
[[Image:BGRATutorial13c.png]]
 
[[Image:BGRATutorial13c.png]]
  
This is strange from a mathematical point of view, but very convenient, because you can use integer coordinates to draw normal 1-pixel wide lines. This way, there is little difference between calls to CanvasBGRA functions and BGRABitmap normal floating point functions.
+
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.
  
=== Create a new project ===
+
=== Erzeugen Sie ein neues Projekt  ===
  
Create a new project and add a reference to [[BGRABitmap]], the same way as in [[BGRABitmap tutorial|the first tutorial]].
+
Erzeugen Sie ein neues Projekt und fügen Sie eine Referenz auf [[BGRABitmap/de|BGRABitmap]] hinzu, genau so wie im [[BGRABitmap tutorial/de|ersten Tutorial]].
  
=== Canvas and BGRACanvas ===
+
=== Canvas und BGRACanvas ===
  
Let's try to show what happens at the pixel level.
+
Versuchen wir zu zeigen, was auf Pixelebene passiert.
  
First, we'll use the standard Canvas :
+
Zuerst verwenden wir die Standardleinwand (Canvas):
 
<delphi>procedure TForm1.FormPaint(Sender: TObject);
 
<delphi>procedure TForm1.FormPaint(Sender: TObject);
 
var image: TBGRABitmap;
 
var image: TBGRABitmap;
Line 50: Line 50:
 
   with image.Canvas do
 
   with image.Canvas do
 
   begin
 
   begin
     //clear with white
+
     //einfach weiß
 
     brush.color := clWhite;
 
     brush.color := clWhite;
 
     FillRect(0,0,image.width,image.height);
 
     FillRect(0,0,image.width,image.height);
     //blue ellipse with black border
+
     //blaue Ellipse mit schwarzem Rand
 
     brush.style := bsClear;
 
     brush.style := bsClear;
 
     pen.color := clBlack;   
 
     pen.color := clBlack;   
 
     Ellipse(0,0,9,9);
 
     Ellipse(0,0,9,9);
 
   end;
 
   end;
   /stretch the image so we can see the pixels
+
   /strecke das Bild, damit wir die Pixel sehen können
 
   BGRAReplace(image,image.Resample(image.Width*10,image.Height*10,rmSimpleStretch));
 
   BGRAReplace(image,image.Resample(image.Width*10,image.Height*10,rmSimpleStretch));
 
   image.Draw(Canvas,0,0,True);
 
   image.Draw(Canvas,0,0,True);
Line 64: Line 64:
 
end;  </delphi>
 
end;  </delphi>
  
The resample option rmSimpleStretch prevents to use interpolation filters.
+
Die Resample-Option 'rmSimpleStretch' bewahrt uns vor Interpolationsfiltern.
  
You should obtain this :
+
Sie sollten dies erhalten:
  
 
[[Image:BGRATutorial13d.png]]
 
[[Image:BGRATutorial13d.png]]
  
The pixels of coordinate 9 are not filled as explained above about rectangle bounds.
+
Die Pixel der Koordinate 9 sind nicht gefüllt (wie bereits oben unter Umgebungsrechteck erklärt).
Now, let's draw this BGRACanvas. Just change the 'with' line :
+
Jetzt zeichnen wir auf die BGRACanvas. Ändern Sie einfach die 'with'-Zeile:
 
<delphi>with image.CanvasBGRA do </delphi>
 
<delphi>with image.CanvasBGRA do </delphi>
  
Now you should obtain this :
+
Jetzt sollten Sie dies erhalten:
  
 
[[Image:BGRATutorial13e.png]]
 
[[Image:BGRATutorial13e.png]]
  
The result is very similar except with antialiasing.
+
Das Ergebnis ist recht ähnlich, abgesehen vom Antialiasing.
  
=== Subtle considerations ===
+
=== Tiefere Überlegungen ===
  
Suppose we want to fill an antialiased ellipse that fit exactly in a 9x9 bitmap.
+
Angenommen, wir wollten eine antialiasierte Ellipse zeichnen, die genau in eine 9x9 Bitmap passt.
We could try with this code :
+
Wir könnten diesen Code versuchen:
 
<delphi>
 
<delphi>
 
procedure TForm1.FormPaint(Sender: TObject);
 
procedure TForm1.FormPaint(Sender: TObject);
Line 95: Line 95:
 
end;    </delphi>
 
end;    </delphi>
  
We obtain :
+
Wir erhalten:
  
 
[[Image:BGRATutorial13f.png]]
 
[[Image:BGRATutorial13f.png]]
  
As you can see, the border is not completely filled. The ellipse is smaller than could be expected. In fact, the center of the ellipse is (4,4) so the left border is at (0,4). But remember it is the center of the pixel. So if we want the ellipse to go to the border of the pixel, we need to add 0.5 to the radius :
+
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:
 
<delphi>  image.FillEllipseAntialias(4,4, 4.5,4.5, BGRABlack); </delphi>
 
<delphi>  image.FillEllipseAntialias(4,4, 4.5,4.5, BGRABlack); </delphi>
  
 
[[Image:BGRATutorial13g.png]]
 
[[Image:BGRATutorial13g.png]]
  
==== Filled shapes with canvas ====
+
==== Gefüllte Formen mit Canvas ====
  
Note that with standard canvas, the result is very surprising. Suppose we want to do the same thing. We could try this :
+
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:
 
<delphi>    brush.color := clWhite;
 
<delphi>    brush.color := clWhite;
 
     FillRect(0,0,image.width,image.height);
 
     FillRect(0,0,image.width,image.height);
Line 113: Line 113:
 
     Ellipse(0,0,9,9);  </delphi>
 
     Ellipse(0,0,9,9);  </delphi>
  
We obtain this :
+
Wir erhalten dies:
  
 
[[Image:BGRATutorial13h.png]]
 
[[Image:BGRATutorial13h.png]]
  
So in this case, there is yet another pixel substracted. The ellipse is 8 pixel wide where as the supplied rectangle is 9 pixel wide.
+
In diesem Fall wurde noch ein weiteres Pixel abgezogen. Die Ellipse ist 8 Pixel breit, wohingegen das bereitgestellte Rechteck 9 Pixel breit ist.
  
 
[[BGRABitmap tutorial 12/de|Voriges Tutorial (Textfunktionen)]]
 
[[BGRABitmap tutorial 12/de|Voriges Tutorial (Textfunktionen)]]
  
 
[[Category:Graphics]]
 
[[Category:Graphics]]

Revision as of 19:58, 30 April 2011

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).

BGRATutorial13a.png

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.

BGRATutorial13b.png

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).

BGRATutorial13c.png

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): <delphi>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; </delphi>

Die Resample-Option 'rmSimpleStretch' bewahrt uns vor Interpolationsfiltern.

Sie sollten dies erhalten:

BGRATutorial13d.png

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: <delphi>with image.CanvasBGRA do </delphi>

Jetzt sollten Sie dies erhalten:

BGRATutorial13e.png

Das Ergebnis ist recht ähnlich, abgesehen vom Antialiasing.

Tiefere Überlegungen

Angenommen, wir wollten eine antialiasierte Ellipse zeichnen, die genau in eine 9x9 Bitmap passt. Wir könnten diesen Code versuchen: <delphi> 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; </delphi>

Wir erhalten:

BGRATutorial13f.png

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: <delphi> image.FillEllipseAntialias(4,4, 4.5,4.5, BGRABlack); </delphi>

BGRATutorial13g.png

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: <delphi> brush.color := clWhite;

   FillRect(0,0,image.width,image.height);
   brush.color := clBlue;
   pen.style := psClear;
   Ellipse(0,0,9,9);  </delphi>

Wir erhalten dies:

BGRATutorial13h.png

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)