source: Common/PixelPointer.pas

Last change on this file was 571, checked in by chronos, 5 months ago
  • Modified: Code cleanup.
File size: 13.0 KB
Line 
1unit PixelPointer;
2
3interface
4
5uses
6 Math, Classes, SysUtils, Graphics;
7
8type
9 TColor32 = type Cardinal;
10 TColor32Component = (ccBlue, ccGreen, ccRed, ccAlpha);
11 TColor32Planes = array[0..3] of Byte;
12
13 { TPixel32 }
14
15 TPixel32 = packed record
16 private
17 procedure SetRGB(AValue: Cardinal); inline;
18 function GetRGB: Cardinal; inline;
19 public
20 class function CreateRGB(R, G, B: Byte): TPixel32; static;
21 class function CreateRGBA(R, G, B, A: Byte): TPixel32; static;
22 property RGB: Cardinal read GetRGB write SetRGB;
23 case Integer of
24 0: (B, G, R, A: Byte);
25 1: (ARGB: TColor32);
26 2: (Planes: TColor32Planes);
27 3: (Components: array[TColor32Component] of Byte);
28 end;
29 PPixel32 = ^TPixel32;
30
31 { TPixelPointer }
32
33 TPixelPointer = record
34 private
35 function GetPixelARGB: TColor32; inline;
36 function GetPixelB: Byte; inline;
37 function GetPixelG: Byte; inline;
38 function GetPixelPlane(Index: Byte): Byte; inline;
39 function GetPixelR: Byte; inline;
40 function GetPixelA: Byte; inline;
41 function GetPixelPlanes: TColor32Planes;
42 function GetPixelRGB: Cardinal; inline;
43 procedure SetPixelARGB(Value: TColor32); inline;
44 procedure SetPixelB(Value: Byte); inline;
45 procedure SetPixelG(Value: Byte); inline;
46 procedure SetPixelPlane(Index: Byte; AValue: Byte); inline;
47 procedure SetPixelR(Value: Byte); inline;
48 procedure SetPixelA(Value: Byte); inline;
49 procedure SetPixelRGB(Value: Cardinal); inline;
50 public
51 Base: PPixel32;
52 Pixel: PPixel32;
53 Line: PPixel32;
54 RelLine: PPixel32;
55 BytesPerPixel: Integer;
56 BytesPerLine: Integer;
57 Data: PPixel32;
58 Width: Integer;
59 Height: Integer;
60 procedure NextLine; inline; // Move pointer to start of next line
61 procedure PreviousLine; inline; // Move pointer to start of previous line
62 procedure NextPixel; inline; // Move pointer to next pixel
63 procedure PreviousPixel; inline; // Move pointer to previous pixel
64 procedure SetXY(X, Y: Integer); inline; // Set pixel position relative to base
65 procedure SetX(X: Integer); inline; // Set horizontal pixel position relative to base
66 procedure CheckRange; inline; // Check if current pixel position is not out of range
67 function PosValid: Boolean;
68 class function Create(Bitmap: TRasterImage; BaseX: Integer = 0; BaseY: Integer = 0): TPixelPointer; static;
69 property PixelARGB: TColor32 read GetPixelARGB write SetPixelARGB;
70 property PixelRGB: Cardinal read GetPixelRGB write SetPixelRGB;
71 property PixelB: Byte read GetPixelB write SetPixelB;
72 property PixelG: Byte read GetPixelG write SetPixelG;
73 property PixelR: Byte read GetPixelR write SetPixelR;
74 property PixelA: Byte read GetPixelA write SetPixelA;
75 property PixelPlane[Index: Byte]: Byte read GetPixelPlane write SetPixelPlane;
76 end;
77 PPixelPointer = ^TPixelPointer;
78
79 function SwapRedBlue(Color: TColor32): TColor32;
80 procedure BitmapCopyRect(DstBitmap: TRasterImage; DstRect: TRect; SrcBitmap: TRasterImage; SrcPos: TPoint);
81 procedure BitmapStretchRect(DstBitmap: TRasterImage; DstRect: TRect;
82 SrcBitmap: TRasterImage; SrcRect: TRect);
83 procedure BitmapFill(Bitmap: TRasterImage; Color: TColor32);
84 procedure BitmapFillRect(Bitmap: TRasterImage; Color: TColor32; Rect: TRect);
85 procedure BitmapSwapRedBlue(Bitmap:TRasterImage);
86 procedure BitmapInvert(Bitmap: TRasterImage);
87 procedure BitmapBlendColor(Bitmap: TRasterImage; Color: TColor32);
88 function Color32(A, R, G, B: Byte): TColor32;
89 function Color32ToPixel32(Color: TColor32): TPixel32;
90 function Pixel32ToColor32(Color: TPixel32): TColor32;
91 function Color32ToColor(Color: TColor32): TColor;
92 function ColorToColor32(Color: TColor): TColor32;
93
94
95implementation
96
97resourcestring
98 SOutOfRange = 'Pixel pointer out of range [X: %d, Y: %d, Width: %d, Height: %d]';
99 SWrongBitmapSize = 'Wrong bitmap size [width: %d, height: %d]';
100
101{ TPixel32 }
102
103function TPixel32.GetRGB: Cardinal;
104begin
105 Result := ARGB and $ffffff;
106end;
107
108class function TPixel32.CreateRGB(R, G, B: Byte): TPixel32;
109begin
110 Result.R := R;
111 Result.G := G;
112 Result.B := B;
113 Result.A := 0;
114end;
115
116class function TPixel32.CreateRGBA(R, G, B, A: Byte): TPixel32;
117begin
118 Result.R := R;
119 Result.G := G;
120 Result.B := B;
121 Result.A := A;
122end;
123
124procedure TPixel32.SetRGB(AValue: Cardinal);
125begin
126 ARGB := (ARGB and $ff000000) or (AValue and $ffffff);
127end;
128
129{ TPixelPointer }
130
131procedure TPixelPointer.NextLine; inline;
132begin
133 Line := Pointer(Line) + BytesPerLine;
134 Pixel := Line;
135end;
136
137procedure TPixelPointer.PreviousLine;
138begin
139 Line := Pointer(Line) - BytesPerLine;
140 Pixel := Line;
141end;
142
143procedure TPixelPointer.NextPixel; inline;
144begin
145 Pixel := Pointer(Pixel) + BytesPerPixel;
146end;
147
148procedure TPixelPointer.PreviousPixel;
149begin
150 Pixel := Pointer(Pixel) - BytesPerPixel;
151end;
152
153procedure TPixelPointer.SetXY(X, Y: Integer); inline;
154begin
155 Line := Pointer(Base) + Y * BytesPerLine;
156 SetX(X);
157end;
158
159procedure TPixelPointer.SetX(X: Integer); inline;
160begin
161 Pixel := Pointer(Line) + X * BytesPerPixel;
162end;
163
164procedure TPixelPointer.CheckRange;
165{$IFOPT R+}
166var
167 X: Integer;
168 Y: Integer;
169{$ENDIF}
170begin
171 {$IFOPT R+}
172 if (PByte(Pixel) < PByte(Data)) or
173 (PByte(Pixel) >= PByte(Data) + Height * BytesPerLine) then begin
174 X := PByte(Pixel) - PByte(Data);
175 Y := Floor(X / BytesPerLine);
176 X := X - Y * BytesPerLine;
177 X := Floor(X / BytesPerPixel);
178 raise Exception.Create(Format(SOutOfRange, [X, Y, Width, Height]));
179 end;
180 {$ENDIF}
181end;
182
183function TPixelPointer.PosValid: Boolean;
184begin
185 Result := not ((PByte(Pixel) < PByte(Data)) or
186 (PByte(Pixel) >= PByte(Data) + Height * BytesPerLine));
187end;
188
189function TPixelPointer.GetPixelPlanes: TColor32Planes;
190begin
191 CheckRange;
192 Result := Pixel^.Planes;
193end;
194
195function TPixelPointer.GetPixelRGB: Cardinal;
196begin
197 CheckRange;
198 Result := Pixel^.RGB;
199end;
200
201procedure TPixelPointer.SetPixelARGB(Value: TColor32);
202begin
203 CheckRange;
204 Pixel^.ARGB := Value;
205end;
206
207procedure TPixelPointer.SetPixelB(Value: Byte);
208begin
209 CheckRange;
210 Pixel^.B := Value;
211end;
212
213procedure TPixelPointer.SetPixelG(Value: Byte);
214begin
215 CheckRange;
216 Pixel^.G := Value;
217end;
218
219procedure TPixelPointer.SetPixelPlane(Index: Byte; AValue: Byte);
220begin
221 CheckRange;
222 Pixel^.Planes[Index] := AValue;
223end;
224
225procedure TPixelPointer.SetPixelR(Value: Byte);
226begin
227 CheckRange;
228 Pixel^.R := Value;
229end;
230
231procedure TPixelPointer.SetPixelA(Value: Byte);
232begin
233 CheckRange;
234 Pixel^.A := Value;
235end;
236
237function TPixelPointer.GetPixelARGB: TColor32;
238begin
239 CheckRange;
240 Result := Pixel^.ARGB;
241end;
242
243function TPixelPointer.GetPixelB: Byte;
244begin
245 CheckRange;
246 Result := Pixel^.B;
247end;
248
249function TPixelPointer.GetPixelG: Byte;
250begin
251 CheckRange;
252 Result := Pixel^.G;
253end;
254
255function TPixelPointer.GetPixelPlane(Index: Byte): Byte;
256begin
257 CheckRange;
258 Result := Pixel^.Planes[Index];
259end;
260
261function TPixelPointer.GetPixelR: Byte;
262begin
263 CheckRange;
264 Result := Pixel^.R;
265end;
266
267function TPixelPointer.GetPixelA: Byte;
268begin
269 CheckRange;
270 Result := Pixel^.A;
271end;
272
273procedure TPixelPointer.SetPixelRGB(Value: Cardinal);
274begin
275 CheckRange;
276 Pixel^.RGB := Value;
277end;
278
279procedure BitmapCopyRect(DstBitmap: TRasterImage; DstRect: TRect;
280 SrcBitmap: TRasterImage; SrcPos: TPoint);
281var
282 SrcPtr, DstPtr: TPixelPointer;
283 X, Y: Integer;
284begin
285 SrcBitmap.BeginUpdate(True);
286 DstBitmap.BeginUpdate(True);
287 SrcPtr := TPixelPointer.Create(SrcBitmap, SrcPos.X, SrcPos.Y);
288 DstPtr := TPixelPointer.Create(DstBitmap, DstRect.Left, DstRect.Top);
289 for Y := 0 to DstRect.Height - 1 do begin
290 for X := 0 to DstRect.Width - 1 do begin
291 DstPtr.PixelARGB := SrcPtr.PixelARGB;
292 SrcPtr.NextPixel;
293 DstPtr.NextPixel;
294 end;
295 SrcPtr.NextLine;
296 DstPtr.NextLine;
297 end;
298 SrcBitmap.EndUpdate;
299 DstBitmap.EndUpdate;
300end;
301
302procedure BitmapStretchRect(DstBitmap: TRasterImage; DstRect: TRect;
303 SrcBitmap: TRasterImage; SrcRect: TRect);
304var
305 SrcPtr, DstPtr: TPixelPointer;
306 X, Y: Integer;
307 XX, YY: Integer;
308 R: TRect;
309 C: TColor32;
310begin
311 if (DstRect.Width = SrcRect.Width) and (DstRect.Height = SrcRect.Height) then begin
312 BitmapCopyRect(DstBitmap, DstRect, SrcBitmap, Point(SrcRect.Left, SrcRect.Top));
313 Exit;
314 end;
315 SrcBitmap.BeginUpdate(True);
316 DstBitmap.BeginUpdate(True);
317 SrcPtr := TPixelPointer.Create(SrcBitmap, SrcRect.Left, SrcRect.Top);
318 DstPtr := TPixelPointer.Create(DstBitmap, DstRect.Left, DstRect.Top);
319 for Y := 0 to DstRect.Height - 1 do begin
320 for X := 0 to DstRect.Width - 1 do begin
321 R := Rect(Trunc(X * SrcRect.Width / DstRect.Width),
322 Trunc(Y * SrcRect.Height / DstRect.Height),
323 Trunc((X + 1) * SrcRect.Width / DstRect.Width),
324 Trunc((Y + 1) * SrcRect.Height / DstRect.Height));
325 DstPtr.SetXY(X, Y);
326 SrcPtr.SetXY(R.Left, R.Top);
327 C := SrcPtr.PixelARGB;
328 DstPtr.PixelARGB := C;
329 for YY := 0 to R.Height - 1 do begin
330 for XX := 0 to R.Width - 1 do begin
331 DstPtr.PixelARGB := C;
332 DstPtr.NextPixel;
333 end;
334 DstPtr.NextLine;
335 end;
336 end;
337 end;
338 SrcBitmap.EndUpdate;
339 DstBitmap.EndUpdate;
340end;
341
342procedure BitmapFill(Bitmap: TRasterImage; Color: TColor32);
343var
344 X, Y: Integer;
345 Ptr: TPixelPointer;
346begin
347 Bitmap.BeginUpdate(True);
348 Ptr := TPixelPointer.Create(Bitmap);
349 for Y := 0 to Bitmap.Height - 1 do begin
350 for X := 0 to Bitmap.Width - 1 do begin
351 Ptr.PixelARGB := Color;
352 Ptr.NextPixel;
353 end;
354 Ptr.NextLine;
355 end;
356 Bitmap.EndUpdate;
357end;
358
359procedure BitmapFillRect(Bitmap: TRasterImage; Color: TColor32; Rect: TRect);
360var
361 X, Y: Integer;
362 Ptr: TPixelPointer;
363begin
364 Bitmap.BeginUpdate(True);
365 Ptr := TPixelPointer.Create(Bitmap, Rect.Left, Rect.Top);
366 for Y := 0 to Rect.Height - 1 do begin
367 for X := 0 to Rect.Width - 1 do begin
368 Ptr.PixelARGB := Color;
369 Ptr.NextPixel;
370 end;
371 Ptr.NextLine;
372 end;
373 Bitmap.EndUpdate;
374end;
375
376procedure BitmapSwapRedBlue(Bitmap: TRasterImage);
377var
378 X, Y: Integer;
379 Ptr: TPixelPointer;
380begin
381 Bitmap.BeginUpdate(True);
382 Ptr := TPixelPointer.Create(Bitmap);
383 for Y := 0 to Bitmap.Height - 1 do begin
384 for X := 0 to Bitmap.Width - 1 do begin
385 Ptr.PixelARGB := SwapRedBlue(Ptr.PixelARGB);
386 Ptr.NextPixel;
387 end;
388 Ptr.NextLine;
389 end;
390 Bitmap.EndUpdate;
391end;
392
393procedure BitmapInvert(Bitmap: TRasterImage);
394var
395 X, Y: Integer;
396 Ptr: TPixelPointer;
397begin
398 Bitmap.BeginUpdate(True);
399 Ptr := TPixelPointer.Create(Bitmap);
400 for Y := 0 to Bitmap.Height - 1 do begin
401 for X := 0 to Bitmap.Width - 1 do begin
402 Ptr.PixelARGB := Ptr.PixelARGB xor $ffffff;
403 Ptr.NextPixel;
404 end;
405 Ptr.NextLine;
406 end;
407 Bitmap.EndUpdate;
408end;
409
410procedure BitmapBlendColor(Bitmap: TRasterImage; Color: TColor32);
411var
412 X, Y: Integer;
413 Ptr: TPixelPointer;
414 A, R, G, B: Word;
415 Pixel: TPixel32;
416begin
417 Pixel := Color32ToPixel32(Color);
418 Bitmap.BeginUpdate(True);
419 Ptr := TPixelPointer.Create(Bitmap);
420 for Y := 0 to Bitmap.Height - 1 do begin
421 for X := 0 to Bitmap.Width - 1 do begin
422 A := Ptr.PixelA; //(Ptr.PixelA + Pixel.A) shr 1;
423 R := (Ptr.PixelR + Pixel.R) shr 1;
424 G := (Ptr.PixelG + Pixel.G) shr 1;
425 B := (Ptr.PixelB + Pixel.B) shr 1;
426 Ptr.PixelARGB := Color32(A, R, G, B);
427 Ptr.NextPixel;
428 end;
429 Ptr.NextLine;
430 end;
431 Bitmap.EndUpdate;
432end;
433
434function Color32(A, R, G, B: Byte): TColor32;
435begin
436 Result := ((A and $ff) shl 24) or ((R and $ff) shl 16) or
437 ((G and $ff) shl 8) or ((B and $ff) shl 0);
438end;
439
440function Color32ToPixel32(Color: TColor32): TPixel32;
441begin
442 Result.ARGB := Color;
443end;
444
445function Pixel32ToColor32(Color: TPixel32): TColor32;
446begin
447 Result := Color.ARGB;
448end;
449
450function Color32ToColor(Color: TColor32): TColor;
451begin
452 Result := ((Color shr 16) and $ff) or (Color and $00ff00) or
453 ((Color and $ff) shl 16);
454end;
455
456function ColorToColor32(Color: TColor): TColor32;
457begin
458 Result := $ff000000 or ((Color shr 16) and $ff) or (Color and $00ff00) or
459 ((Color and $ff) shl 16);
460end;
461
462class function TPixelPointer.Create(Bitmap: TRasterImage; BaseX: Integer;
463 BaseY: Integer): TPixelPointer;
464begin
465 Result.Width := Bitmap.Width;
466 Result.Height := Bitmap.Height;
467 if (Result.Width < 0) or (Result.Height < 0) then
468 raise Exception.Create(Format(SWrongBitmapSize, [Result.Width, Result.Height]));
469 Result.BytesPerLine := Bitmap.RawImage.Description.BytesPerLine;
470 Result.BytesPerPixel := Bitmap.RawImage.Description.BitsPerPixel shr 3;
471 Result.Data := PPixel32(Bitmap.RawImage.Data);
472 Result.Base := PPixel32(Bitmap.RawImage.Data + BaseX * Result.BytesPerPixel +
473 BaseY * Result.BytesPerLine);
474 Result.SetXY(0, 0);
475end;
476
477function SwapRedBlue(Color: TColor32): TColor32;
478begin
479 Result := (Color and $ff00ff00) or ((Color and $ff) shl 16) or ((Color shr 16) and $ff);
480end;
481
482end.
Note: See TracBrowser for help on using the repository browser.