BGRABitmap tutorial 13/de

From Lazarus wiki
Revision as of 16:54, 30 April 2011 by Billyraybones (talk | contribs) (partially translated)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

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?

Obere, linke Distanz bei Fließkommakoordinaten

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

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.

Pixel-center floating point coordinates

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

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.

Create a new project

Create a new project and add a reference to BGRABitmap, the same way as in the first tutorial.

Canvas and BGRACanvas

Let's try to show what happens at the pixel level.

First, we'll use the standard Canvas : <delphi>procedure TForm1.FormPaint(Sender: TObject); var image: TBGRABitmap; begin

 image := TBGRABitmap.Create(10,10);
 with image.Canvas do
 begin
   //clear with white
   brush.color := clWhite;
   FillRect(0,0,image.width,image.height);
   //blue ellipse with black border
   brush.style := bsClear;
   pen.color := clBlack;  
   Ellipse(0,0,9,9);
 end;
 /stretch the image so we can see the pixels
 BGRAReplace(image,image.Resample(image.Width*10,image.Height*10,rmSimpleStretch));
 image.Draw(Canvas,0,0,True);
 image.free;

end; </delphi>

The resample option rmSimpleStretch prevents to use interpolation filters.

You should obtain this :

BGRATutorial13d.png

The pixels of coordinate 9 are not filled as explained above about rectangle bounds. Now, let's draw this BGRACanvas. Just change the 'with' line : <delphi>with image.CanvasBGRA do </delphi>

Now you should obtain this :

BGRATutorial13e.png

The result is very similar except with antialiasing.

Subtle considerations

Suppose we want to fill an antialiased ellipse that fit exactly in a 9x9 bitmap. We could try with this code : <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>

We obtain :

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

BGRATutorial13g.png

Filled shapes with canvas

Note that with standard canvas, the result is very surprising. Suppose we want to do the same thing. We could try this : <delphi> brush.color := clWhite;

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

We obtain this :

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.

Voriges Tutorial (Textfunktionen)