Sign in Join
Wiki copytemporary

BGRABitmap tutorial 4: what changed

Revision 1 to 2. 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
53-<figure>
54-<img src="BGRATutorial4.png" title="BGRATutorial4.png" />
55-<figcaption>BGRATutorial4.png</figcaption>
56-</figure>
53+![](/wiki-images/8/8b/BGRATutorial4.png)
5754
5855## Using HSLA colorspace
5956
6057You 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.
6158
6259``` pascal
6360procedure TForm1.FormPaint(Sender: TObject);
6461var x,y: integer;
6562 p: PBGRAPixel;
6663 image: TBGRABitmap;
6764 hsla: THSLAPixel;
6865begin
6966 image := TBGRABitmap.Create(ClientWidth,ClientHeight);
7067 hsla.lightness := 32768;
7168 hsla.alpha := 65535;
7269 for y := 0 to image.Height-1 do
7370 begin
7471 p := image.Scanline[y];
7572 hsla.saturation := y*65536 div image.Height;
7673 for x := 0 to image.Width-1 do
7774 begin
7875 hsla.hue := x*65536 div image.Width;
7976 p^:= HSLAToBGRA(hsla);
8077 inc(p);
8178 end;
8279 end;
8380 image.InvalidateBitmap; // changed by direct access
8481
8582 image.Draw(Canvas,0,0,True);
8683 image.free;
8784end;
8885```
8986
90-<figure>
91-<img src="BGRATutorial4b.png" title="BGRATutorial4b.png" />
92-<figcaption>BGRATutorial4b.png</figcaption>
93-</figure>
87+![](/wiki-images/1/1b/BGRATutorial4b.png)
9488
9589#### Color correction
9690
9791HSLA 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:
9892
9993``` pascal
10094hsla.hue := GtoH(x*65536 div image.Width);
10195```
10296
10397Notice 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.
10498
10599The code simple becomes:
106100
107101``` pascal
108102procedure TForm1.FormPaint(Sender: TObject);
109103var x,y: integer;
110104 p: PBGRAPixel;
111105 image: TBGRABitmap;
112106 hsla: THSLAPixel;
113107begin
114108 image := TBGRABitmap.Create(ClientWidth,ClientHeight);
115109 hsla.lightness := 32768;
116110 hsla.alpha := 65535;
117111 for y := 0 to image.Height-1 do
118112 begin
119113 p := image.Scanline[y];
120114 hsla.saturation := y*65536 div image.Height;
121115 for x := 0 to image.Width-1 do
122116 begin
123117 hsla.hue := x*65536 div image.Width;
124118 p^:= GSBAToBGRA(hsla);
125119 inc(p);
126120 end;
127121 end;
128122 image.InvalidateBitmap; // changed by direct access
129123
130124 image.Draw(Canvas,0,0,True);
131125 image.free;
132126end;
133127```
134128
135129Note that the THSLAPixel type is used, whatever the correction of the color model.
136130
137131### Run the program
138132
139133With full color correction, the gradient is more progressive, and looks like what you would obtain with the Lab color model.
140134
141-<figure>
142-<img src="BGRATutorial4c.png" title="BGRATutorial4c.png" />
143-<figcaption>BGRATutorial4c.png</figcaption>
144-</figure>
135+![](/wiki-images/a/a6/BGRATutorial4c.png)
145136
146137## Using TXYZABitmap
147138
148139Instead 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.
149140
150141The 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.
151142
152143The 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.
153144
154145Also 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.
155146
156147To render on screen, the bitmap needs to be drawn on a BGRA bitmap.
157148
158149``` pascal
159150uses BGRABitmap, BGRABitmapTypes, XYZABitmap;
160151
161152procedure TForm1.FormPaint(Sender: TObject);
162153var x,y: integer;
163154 image: TBGRABitmap;
164155 xyzImage: TXYZABitmap;
165156 p: PXYZA;
166157 xyz: TXYZA;
167158begin
168159 // create a bitmap with XYZA colorspace
169160 // and take into account the scale factor (for MacOS)
170161 xyzImage := TXYZABitmap.Create(round(ClientWidth * GetCanvasScaleFactor),
171162 round(ClientHeight * GetCanvasScaleFactor));
172163 xyz.alpha := 1;
173164 xyz.Y := 0.5;
174165 for y := 0 to xyzImage.Height-1 do
175166 begin
176167 p := xyzImage.Scanline[y];
177168 xyz.x := 0.35 + y/xyzImage.Height*0.3;
178169 for x := 0 to xyzImage.Width-1 do
179170 begin
180171 xyz.z := 0.15 + x/xyzImage.Width*0.5;
181172 p^:= xyz;
182173 inc(p);
183174 end;
184175 end;
185176 xyzImage.InvalidateBitmap; // changed by direct access
186177
187178 // draw the XYZA bitmap on a BGRA bitmap for display
188179 image := TBGRABitmap.Create(xyzImage.Width, xyzImage.Height);
189180 image.PutImage(0,0, xyzImage, dmSet);
190181 // stretch (reduce) because of scale factor
191182 image.Draw(Canvas, rect(0,0,ClientWidth,ClientHeight), True);
192183 image.free;
193184end;
194185```
195186
196-<figure>
197187<img src="BGRATutorial4d.png" title="BGRATutorial4d.png" width="392" />
198-<figcaption>BGRATutorial4d.png</figcaption>
199-</figure>
200188
201189[[BGRABitmap tutorial 3|Previous tutorial (drawing with the mouse)]] \| [[BGRABitmap tutorial 5|Next tutorial (layers and masks)]]
202190
203191---
204192*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).*
205193Category: BGRABitmap
206194Category: Graphics

Back to history