BGRABitmap tutorial 4

From Free Pascal wiki
Jump to: navigation, search

Deutsch (de) | English (en) | Français (fr) | Español (es) | Edit

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

This tutorial shows you how to access directly to pixels. See reference on direct pixel access.

Create a new project

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

Add a painting handler

With the object inspector, add an OnPaint handler and write :

procedure TForm1.FormPaint(Sender: TObject);
var x,y: integer;
    p: PBGRAPixel;
    image: TBGRABitmap;
begin
  image := TBGRABitmap.Create(ClientWidth,ClientHeight);
 
  for y := 0 to image.Height-1 do
  begin
    p := image.Scanline[y];
    for x := 0 to image.Width-1 do
    begin
      p^.red := x*256 div image.Width;
      p^.green := y*256 div image.Height;
      p^.blue := 0;
      p^.alpha := 255;
      inc(p);
    end;
  end;
  image.InvalidateBitmap; // changed by direct access
 
  image.Draw(Canvas,0,0,True);
  image.free;
end;

This procedure creates a bitmap of the same size as the available client space. Then the loops access directly to pixel data to render a bidimensional gradient. Finally the image is drawn and freed.

To access to bitmap data, you can either use Data, if you do not mind the line order, or Scanline to access to a specific line. Within a line, pixels are ordered from left to right. Each component is defined. For example :

p^.red := x*256 div image.Width;

Defines a red component varying from 0 to 255 from left to right. The maximum value image.Width is never reached by x, so the red component never reach 256.

Run the program

You should see a form with a gradient where corners are black, red, yellow and green. When you resize the form, the gradient is resized accordingly.

BGRATutorial4.png

Using HSLA colorspace

You can use hue, saturation, and lightness. To do this, declare a THSLAPixel. It's values range from 0 to 65535. To convert it to standard RGB pixel, use HSLAToBGRA.

procedure TForm1.FormPaint(Sender: TObject);
var x,y: integer;
    p: PBGRAPixel;
    image: TBGRABitmap;
    hsla: THSLAPixel;
begin
  image := TBGRABitmap.Create(ClientWidth,ClientHeight);
  hsla.lightness := 32768;
  hsla.alpha := 65535;
  for y := 0 to image.Height-1 do
  begin
    p := image.Scanline[y];
    hsla.saturation := y*65536 div image.Height;
    for x := 0 to image.Width-1 do
    begin
      hsla.hue := x*65536 div image.Width;
      p^:= HSLAToBGRA(hsla);
      inc(p);
    end;
  end;
  image.InvalidateBitmap; // changed by direct access
 
  image.Draw(Canvas,0,0,True);
  image.free;
end;

BGRATutorial4b.png

Color correction

HSLA colors have gamma correction, but there are other possible corrections. For example, H means "hue". In the classical version of HSLA model, each range between primary colors (red/green/blue) is represented by 120 degrees, which equals 21845 colors in THSLAPixel. However, we do not perceive the same differences of colors in these different ranges. The functions HtoG and GtoH apply or unapply a correction, where in the G hue, ranges are not of the same size. To get a corrected hue, write:

hsla.hue := GtoH(x*65536 div image.Width);

Notice that the range of oranges is wider. Finally, in the HSLA model, the lightness L does not correspond to the perceived lightness. Instead of only correcting the hue, you can use GSBAToBGRA and BGRAToGSBA instead of HLSAToBGRA and BGRAToHSLA. The G here means that the hue is automatically corrected and the B means it's the perceived lightness (sometimes called Brightness) which is taken into account. So you don't need to call GtoH and HtoG explicitely.

The code simple becomes :

procedure TForm1.FormPaint(Sender: TObject);
var x,y: integer;
    p: PBGRAPixel;
    image: TBGRABitmap;
    hsla: THSLAPixel;
begin
  image := TBGRABitmap.Create(ClientWidth,ClientHeight);
  hsla.lightness := 32768;
  hsla.alpha := 65535;
  for y := 0 to image.Height-1 do
  begin
    p := image.Scanline[y];
    hsla.saturation := y*65536 div image.Height;
    for x := 0 to image.Width-1 do
    begin
      hsla.hue := x*65536 div image.Width;
      p^:= GSBAToBGRA(hsla);
      inc(p);
    end;
  end;
  image.InvalidateBitmap; // changed by direct access
 
  image.Draw(Canvas,0,0,True);
  image.free;
end;

Note that the THSLAPixel type is used, whatever the correction of the color model.

Run the program

With full color correction, the gradient is more progressive, and looks like what you would obtain with the Lab color model.

BGRATutorial4c.png


Previous tutorial (drawing with the mouse) | Next tutorial (layers and masks)