Sign in Join
Wiki copytemporary

BGRABitmap tutorial 4: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11This tutorial shows you how to access directly to pixels. See reference on [[TBGRABitmap class|direct pixel access]].
22
33## Create a new project
44
55Create a new project and add a reference to [[BGRABitmap]], the same way as in [[BGRABitmap tutorial|the first tutorial]].
66
77### Add a painting handler
88
99With the object inspector, add an OnPaint handler and write:
1010
1111``` pascal
1212procedure TForm1.FormPaint(Sender: TObject);
1313var
1414 x, y: integer;
1515 p: PBGRAPixel;
1616 image: TBGRABitmap;
1717begin
1818 image := TBGRABitmap.Create(ClientWidth, ClientHeight);
1919
2020 for y := 0 to image.Height-1 do
2121 begin
2222 p := image.Scanline[y];
2323 for x := 0 to image.Width-1 do
2424 begin
2525 p^.red := x * 256 div image.Width;
2626 p^.green := y * 256 div image.Height;
2727 p^.blue := 0;
2828 p^.alpha := 255;
2929 inc(p);
3030 end;
3131 end;
3232 image.InvalidateBitmap; // changed by direct access
3333
3434 image.Draw(Canvas, 0, 0, True);
3535 image.free;
3636end;
3737```
3838
3939This 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.
4040
4141To 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:
4242
4343``` pascal
4444p^.red := x*256 div image.Width;
4545```
4646
4747Defines 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.
4848
4949### Run the program
5050
5151You 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.
5252
5353![](/wiki-images/8/8b/BGRATutorial4.png)
5454
5555## Using HSLA colorspace
5656
5757You can use hue, saturation, and lightness. To do this, declare a [[BGRABitmap Pixel types|THSLAPixel]]. It's values range from 0 to 65535. To convert it to standard RGB pixel, use HSLAToBGRA.
5858
5959``` pascal
6060procedure TForm1.FormPaint(Sender: TObject);
6161var x,y: integer;
6262 p: PBGRAPixel;
6363 image: TBGRABitmap;
6464 hsla: THSLAPixel;
6565begin
6666 image := TBGRABitmap.Create(ClientWidth,ClientHeight);
6767 hsla.lightness := 32768;
6868 hsla.alpha := 65535;
6969 for y := 0 to image.Height-1 do
7070 begin
7171 p := image.Scanline[y];
7272 hsla.saturation := y*65536 div image.Height;
7373 for x := 0 to image.Width-1 do
7474 begin
7575 hsla.hue := x*65536 div image.Width;
7676 p^:= HSLAToBGRA(hsla);
7777 inc(p);
7878 end;
7979 end;
8080 image.InvalidateBitmap; // changed by direct access
8181
8282 image.Draw(Canvas,0,0,True);
8383 image.free;
8484end;
8585```
8686
8787![](/wiki-images/1/1b/BGRATutorial4b.png)
8888
8989#### Color correction
9090
9191HSLA 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 [[BGRABitmap Pixel types|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:
9292
9393``` pascal
9494hsla.hue := GtoH(x*65536 div image.Width);
9595```
9696
9797Notice 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.
9898
9999The code simple becomes:
100100
101101``` pascal
102102procedure TForm1.FormPaint(Sender: TObject);
103103var x,y: integer;
104104 p: PBGRAPixel;
105105 image: TBGRABitmap;
106106 hsla: THSLAPixel;
107107begin
108108 image := TBGRABitmap.Create(ClientWidth,ClientHeight);
109109 hsla.lightness := 32768;
110110 hsla.alpha := 65535;
111111 for y := 0 to image.Height-1 do
112112 begin
113113 p := image.Scanline[y];
114114 hsla.saturation := y*65536 div image.Height;
115115 for x := 0 to image.Width-1 do
116116 begin
117117 hsla.hue := x*65536 div image.Width;
118118 p^:= GSBAToBGRA(hsla);
119119 inc(p);
120120 end;
121121 end;
122122 image.InvalidateBitmap; // changed by direct access
123123
124124 image.Draw(Canvas,0,0,True);
125125 image.free;
126126end;
127127```
128128
129129Note that the THSLAPixel type is used, whatever the correction of the color model.
130130
131131### Run the program
132132
133133With full color correction, the gradient is more progressive, and looks like what you would obtain with the Lab color model.
134134
135135![](/wiki-images/a/a6/BGRATutorial4c.png)
136136
137137## Using TXYZABitmap
138138
139139Instead of converting directly the values of pixels, it is possible to use a bitmap with another pixel format. Here is how to use the XYZA colorspace.
140140
141141The TXYZA type contains floating point values from 0 to 1. In the example, the Y value (lightness) is set to 0.5 while the X and Z values varies to express different hues.
142142
143143The X and Z channels can be greater than one depending on the illuminant and typically in daylight the Z value for the brightest white is slightly greater than 1. In theory the Y channel can be greater than one as well if it expresses a light source stronger than the illuminant, but that will saturate when rendering it on a screen.
144144
145145Also here the GetCanvasScaleFactor function (value 1 or greater) is used to determine if there is a Retina display for which the coordinates can be double the pixel size. So in this case, we need to prepare a bitmap that is twice as big and in the end draw it zoomed out.
146146
147147To render on screen, the bitmap needs to be drawn on a BGRA bitmap.
148148
149149``` pascal
150150uses BGRABitmap, BGRABitmapTypes, XYZABitmap;
151151
152152procedure TForm1.FormPaint(Sender: TObject);
153153var x,y: integer;
154154 image: TBGRABitmap;
155155 xyzImage: TXYZABitmap;
156156 p: PXYZA;
157157 xyz: TXYZA;
158158begin
159159 // create a bitmap with XYZA colorspace
160160 // and take into account the scale factor (for MacOS)
161161 xyzImage := TXYZABitmap.Create(round(ClientWidth * GetCanvasScaleFactor),
162162 round(ClientHeight * GetCanvasScaleFactor));
163163 xyz.alpha := 1;
164164 xyz.Y := 0.5;
165165 for y := 0 to xyzImage.Height-1 do
166166 begin
167167 p := xyzImage.Scanline[y];
168168 xyz.x := 0.35 + y/xyzImage.Height*0.3;
169169 for x := 0 to xyzImage.Width-1 do
170170 begin
171171 xyz.z := 0.15 + x/xyzImage.Width*0.5;
172172 p^:= xyz;
173173 inc(p);
174174 end;
175175 end;
176176 xyzImage.InvalidateBitmap; // changed by direct access
177177
178178 // draw the XYZA bitmap on a BGRA bitmap for display
179179 image := TBGRABitmap.Create(xyzImage.Width, xyzImage.Height);
180180 image.PutImage(0,0, xyzImage, dmSet);
181181 // stretch (reduce) because of scale factor
182182 image.Draw(Canvas, rect(0,0,ClientWidth,ClientHeight), True);
183183 image.free;
184184end;
185185```
186186
187-<img src="BGRATutorial4d.png" title="BGRATutorial4d.png" width="392" />
187+![](/wiki-images/4/41/BGRATutorial4d.png)
188188
189189[[BGRABitmap tutorial 3|Previous tutorial (drawing with the mouse)]] \| [[BGRABitmap tutorial 5|Next tutorial (layers and masks)]]
190190
191191---
192192*From the Free Pascal wiki, page "BGRABitmap tutorial 4", as it stood on 2023-01-02 after a change by Circular, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
193193Category: BGRABitmap
194194Category: Graphics

Back to history