source: trunk/Packages/Graphics32/GR32_OrdinalMaps.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 32.9 KB
Line 
1unit GR32_OrdinalMaps;
2
3(* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1 or LGPL 2.1 with linking exception
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Alternatively, the contents of this file may be used under the terms of the
17 * Free Pascal modified version of the GNU Lesser General Public License
18 * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
19 * of this license are applicable instead of those above.
20 * Please see the file LICENSE.txt for additional information concerning this
21 * license.
22 *
23 * The Original Code is Graphics32
24 *
25 * The Initial Developer of the Original Code is
26 * Mattias Andersson
27 * (parts of this unit were merged from GR32_ByteMaps.pas by Alex A. Denisov)
28 *
29 * Portions created by the Initial Developer are Copyright (C) 2000-2009
30 * the Initial Developer. All Rights Reserved.
31 *
32 * Contributor(s):
33 * Michael Hansen
34 *
35 * ***** END LICENSE BLOCK ***** *)
36
37interface
38
39{$I GR32.inc}
40
41uses
42{$IFDEF FPC}
43 Controls, Graphics,
44 {$IFDEF Windows}
45 Windows,
46 {$ENDIF}
47{$ELSE}
48 Windows, Controls, Graphics,
49{$ENDIF}
50 Classes, SysUtils, GR32;
51
52type
53 TConversionType = (ctRed, ctGreen, ctBlue, ctAlpha, ctUniformRGB,
54 ctWeightedRGB);
55
56{$IFDEF FPC}
57 PInteger = ^Integer;
58{$ENDIF}
59
60 TBooleanMap = class(TCustomMap)
61 private
62 function GetValue(X, Y: Integer): Boolean;
63 procedure SetValue(X, Y: Integer; const Value: Boolean);
64 protected
65 FBits: PByteArray;
66 procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); override;
67 public
68 constructor Create; overload; override;
69 destructor Destroy; override;
70
71 function Empty: Boolean; override;
72 procedure Clear(FillValue: Byte);
73 procedure ToggleBit(X, Y: Integer);
74
75 property Value[X, Y: Integer]: Boolean read GetValue write SetValue; default;
76 property Bits: PByteArray read FBits;
77 end;
78
79 TByteMap = class(TCustomMap)
80 private
81 function GetValue(X, Y: Integer): Byte; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
82 function GetValPtr(X, Y: Integer): PByte; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
83 procedure SetValue(X, Y: Integer; Value: Byte); {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
84 function GetScanline(Y: Integer): PByteArray;
85 protected
86 FBits: PByteArray;
87 procedure AssignTo(Dst: TPersistent); override;
88 procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); override;
89 public
90 constructor Create; overload; override;
91 destructor Destroy; override;
92
93 procedure Assign(Source: TPersistent); override;
94 function Empty: Boolean; override;
95 procedure Clear(FillValue: Byte);
96
97 procedure Multiply(Value: Byte);
98 procedure Add(Value: Byte);
99 procedure Sub(Value: Byte);
100
101 procedure ReadFrom(Source: TCustomBitmap32; Conversion: TConversionType);
102 procedure WriteTo(Dest: TCustomBitmap32; Conversion: TConversionType); overload;
103 procedure WriteTo(Dest: TCustomBitmap32; const Palette: TPalette32); overload;
104
105 procedure DrawTo(Dest: TCustomBitmap32; X, Y: Integer; Color: TColor32); overload;
106 procedure DrawTo(Dest: TCustomBitmap32; Rect: TRect; Color: TColor32); overload;
107
108 procedure Downsample(Factor: Byte); overload;
109 procedure Downsample(Dest: TByteMap; Factor: Byte); overload;
110
111 procedure FlipHorz(Dst: TByteMap = nil);
112 procedure FlipVert(Dst: TByteMap = nil);
113 procedure Rotate90(Dst: TByteMap = nil);
114 procedure Rotate180(Dst: TByteMap = nil);
115 procedure Rotate270(Dst: TByteMap = nil);
116
117 property Bits: PByteArray read FBits;
118 property Scanline[Y: Integer]: PByteArray read GetScanline;
119 property ValPtr[X, Y: Integer]: PByte read GetValPtr;
120 property Value[X, Y: Integer]: Byte read GetValue write SetValue; default;
121 end;
122
123 { TWordMap }
124
125 TWordMap = class(TCustomMap)
126 private
127 function GetValPtr(X, Y: Integer): PWord; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
128 function GetValue(X, Y: Integer): Word; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
129 procedure SetValue(X, Y: Integer; const Value: Word); {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
130 function GetScanline(Y: Integer): PWordArray;
131 protected
132 FBits: PWordArray;
133 procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); override;
134 public
135 constructor Create; overload; override;
136 destructor Destroy; override;
137
138 procedure Assign(Source: TPersistent); override;
139 function Empty: Boolean; override;
140 procedure Clear(FillValue: Word);
141
142 property ValPtr[X, Y: Integer]: PWord read GetValPtr;
143 property Value[X, Y: Integer]: Word read GetValue write SetValue; default;
144 property Bits: PWordArray read FBits;
145 property Scanline[Y: Integer]: PWordArray read GetScanline;
146 end;
147
148 { TIntegerMap }
149
150 TIntegerMap = class(TCustomMap)
151 private
152 function GetValPtr(X, Y: Integer): PInteger; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
153 function GetValue(X, Y: Integer): Integer; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
154 procedure SetValue(X, Y: Integer; const Value: Integer); {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
155 function GetScanline(Y: Integer): PIntegerArray;
156 protected
157 FBits: PIntegerArray;
158 procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); override;
159 public
160 constructor Create; overload; override;
161 destructor Destroy; override;
162
163 procedure Assign(Source: TPersistent); override;
164 function Empty: Boolean; override;
165 procedure Clear(FillValue: Integer = 0);
166
167 property ValPtr[X, Y: Integer]: PInteger read GetValPtr;
168 property Value[X, Y: Integer]: Integer read GetValue write SetValue; default;
169 property Bits: PIntegerArray read FBits;
170 property Scanline[Y: Integer]: PIntegerArray read GetScanline;
171 end;
172
173 { TCardinalMap }
174
175 TCardinalMap = class(TCustomMap)
176 private
177 function GetValPtr(X, Y: Cardinal): PCardinal; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
178 function GetValue(X, Y: Cardinal): Cardinal; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
179 procedure SetValue(X, Y: Cardinal; const Value: Cardinal); {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
180 function GetScanline(Y: Integer): PCardinalArray;
181 protected
182 FBits: PCardinalArray;
183 procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); override;
184 public
185 constructor Create; overload; override;
186 destructor Destroy; override;
187
188 procedure Assign(Source: TPersistent); override;
189 function Empty: Boolean; override;
190 procedure Clear(FillValue: Cardinal = 0);
191
192 property ValPtr[X, Y: Cardinal]: PCardinal read GetValPtr;
193 property Value[X, Y: Cardinal]: Cardinal read GetValue write SetValue; default;
194 property Bits: PCardinalArray read FBits;
195 property Scanline[Y: Integer]: PCardinalArray read GetScanline;
196 end;
197
198 { TFloatMap }
199
200 TFloatMap = class(TCustomMap)
201 private
202 function GetValPtr(X, Y: Integer): GR32.PFloat; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
203 function GetValue(X, Y: Integer): TFloat; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
204 procedure SetValue(X, Y: Integer; const Value: TFloat); {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
205 function GetScanline(Y: Integer): PFloatArray;
206 protected
207 FBits: PFloatArray;
208 procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); override;
209 public
210 constructor Create; overload; override;
211 destructor Destroy; override;
212
213 procedure Assign(Source: TPersistent); override;
214 function Empty: Boolean; override;
215 procedure Clear; overload;
216 procedure Clear(FillValue: TFloat); overload;
217
218 property ValPtr[X, Y: Integer]: PFloat read GetValPtr;
219 property Value[X, Y: Integer]: TFloat read GetValue write SetValue; default;
220 property Bits: PFloatArray read FBits;
221 property Scanline[Y: Integer]: PFloatArray read GetScanline;
222 end;
223
224{$IFDEF COMPILER2010}
225
226 { TGenericMap<T> }
227
228 TGenericMap<T> = class(TCustomMap)
229 private
230 function GetValue(X, Y: Integer): T; {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
231 procedure SetValue(X, Y: Integer; const Value: T); {$IFDEF INLININGSUPPORTED} inline; {$ENDIF}
232 protected
233 FBits: Pointer;
234 procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); override;
235 public
236 constructor Create; overload; override;
237 destructor Destroy; override;
238
239 procedure Assign(Source: TPersistent); override;
240 function Empty: Boolean; override;
241 procedure Clear; overload;
242 procedure Clear(FillValue: T); overload;
243
244 property Value[X, Y: Integer]: T read GetValue write SetValue; default;
245 property Bits: Pointer read FBits;
246 end;
247
248{$ENDIF}
249
250implementation
251
252uses
253 Math, GR32_LowLevel, GR32_Blend, GR32_Resamplers;
254
255function Bytes(Bits: Integer): Integer;
256begin
257 Result := (Bits - 1) shr 3 + 1;
258end;
259
260{ TBooleanMap }
261
262constructor TBooleanMap.Create;
263begin
264 FreeMem(FBits);
265 inherited Create;
266end;
267
268procedure TBooleanMap.ChangeSize(var Width, Height: Integer; NewWidth,
269 NewHeight: Integer);
270begin
271 ReallocMem(FBits, Bytes(NewWidth * NewHeight));
272 Width := NewWidth;
273 Height := NewHeight;
274end;
275
276procedure TBooleanMap.Clear(FillValue: Byte);
277begin
278 FillChar(FBits^, Bytes(Width * Height), FillValue);
279end;
280
281destructor TBooleanMap.Destroy;
282begin
283 FBits := nil;
284 inherited;
285end;
286
287function TBooleanMap.Empty: Boolean;
288begin
289 Result := not Assigned(FBits);
290end;
291
292function TBooleanMap.GetValue(X, Y: Integer): Boolean;
293begin
294 X := X + Y * Width;
295 Result := FBits^[X shr 3] and (1 shl (X and 7)) <> 0; //Boolean(FBits^[X shr 3] and (1 shl (X and 7)));
296end;
297
298procedure TBooleanMap.SetValue(X, Y: Integer; const Value: Boolean);
299begin
300 X := Y * Width + X;
301 if Value then
302 FBits^[X shr 3] := FBits^[X shr 3] or (1 shl (X and 7))
303 else
304 FBits^[X shr 3] := FBits^[X shr 3] and ((1 shl (X and 7)) xor $FF);
305end;
306
307procedure TBooleanMap.ToggleBit(X, Y: Integer);
308begin
309 X := Y * Width + X;
310 FBits^[X shr 3] := FBits^[X shr 3] xor (1 shl (X and 7));
311end;
312
313{ TByteMap }
314
315constructor TByteMap.Create;
316begin
317 FBits := nil;
318 inherited Create;
319end;
320
321destructor TByteMap.Destroy;
322begin
323 FreeMem(FBits);
324 inherited;
325end;
326
327procedure TByteMap.Downsample(Factor: Byte);
328begin
329 // downsample inplace
330 case Factor of
331 2:
332 DownsampleByteMap2x(Self, Self);
333 3:
334 DownsampleByteMap3x(Self, Self);
335 4:
336 DownsampleByteMap4x(Self, Self);
337 6:
338 begin
339 DownsampleByteMap3x(Self, Self);
340 DownsampleByteMap2x(Self, Self);
341 end;
342 8:
343 begin
344 DownsampleByteMap4x(Self, Self);
345 DownsampleByteMap2x(Self, Self);
346 end;
347 9:
348 begin
349 DownsampleByteMap3x(Self, Self);
350 DownsampleByteMap3x(Self, Self);
351 end;
352 12:
353 begin
354 DownsampleByteMap4x(Self, Self);
355 DownsampleByteMap3x(Self, Self);
356 end;
357 16:
358 begin
359 DownsampleByteMap4x(Self, Self);
360 DownsampleByteMap4x(Self, Self);
361 end;
362 18:
363 begin
364 DownsampleByteMap3x(Self, Self);
365 DownsampleByteMap3x(Self, Self);
366 DownsampleByteMap2x(Self, Self);
367 end;
368 24:
369 begin
370 DownsampleByteMap4x(Self, Self);
371 DownsampleByteMap3x(Self, Self);
372 DownsampleByteMap2x(Self, Self);
373 end;
374 27:
375 begin
376 DownsampleByteMap3x(Self, Self);
377 DownsampleByteMap3x(Self, Self);
378 DownsampleByteMap3x(Self, Self);
379 end;
380 32:
381 begin
382 DownsampleByteMap4x(Self, Self);
383 DownsampleByteMap4x(Self, Self);
384 DownsampleByteMap2x(Self, Self);
385 end;
386 end;
387end;
388
389procedure TByteMap.Downsample(Dest: TByteMap; Factor: Byte);
390
391 procedure DownsampleAndMove;
392 var
393 Temp: TByteMap;
394 Y: Integer;
395 begin
396 // clone destination and downsample inplace
397 Temp := TByteMap.Create;
398 Temp.Assign(Self);
399 Temp.Downsample(Factor);
400
401 // copy downsampled result
402 Dest.SetSize(Width div Factor, Height div Factor);
403 for Y := 0 to Dest.Height - 1 do
404 Move(Temp.Scanline[Y]^, Dest.Scanline[Y]^, Dest.Width);
405 end;
406
407begin
408 // downsample directly
409 if (Dest = Self) or not (Factor in [2, 3, 4]) then
410 begin
411 DownsampleAndMove;
412 Exit;
413 end;
414
415 case Factor of
416 2:
417 begin
418 Dest.SetSize(Width div 2, Height div 2);
419 DownsampleByteMap2x(Self, Dest);
420 end;
421 3:
422 begin
423 // downsample directly
424 Dest.SetSize(Width div 3, Height div 3);
425 DownsampleByteMap3x(Self, Dest);
426 end;
427 4:
428 begin
429 // downsample directly
430 Dest.SetSize(Width div 4, Height div 4);
431 DownsampleByteMap4x(Self, Dest);
432 end;
433 end;
434end;
435
436procedure TByteMap.Assign(Source: TPersistent);
437begin
438 BeginUpdate;
439 try
440 if Source is TByteMap then
441 begin
442 inherited SetSize(TByteMap(Source).Width, TByteMap(Source).Height);
443 Move(TByteMap(Source).Bits[0], Bits[0], Width * Height);
444 end
445 else if Source is TBitmap32 then
446 ReadFrom(TBitmap32(Source), ctWeightedRGB)
447 else
448 inherited;
449 finally
450 EndUpdate;
451 Changed;
452 end;
453end;
454
455procedure TByteMap.AssignTo(Dst: TPersistent);
456begin
457 if Dst is TBitmap32 then WriteTo(TBitmap32(Dst), ctUniformRGB)
458 else inherited;
459end;
460
461procedure TByteMap.ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer);
462begin
463 ReallocMem(FBits, NewWidth * NewHeight);
464 Width := NewWidth;
465 Height := NewHeight;
466end;
467
468procedure TByteMap.Clear(FillValue: Byte);
469begin
470 FillChar(Bits^, Width * Height, FillValue);
471 Changed;
472end;
473
474function TByteMap.Empty: Boolean;
475begin
476 Result := False;
477 if (Width = 0) or (Height = 0) or (FBits = nil) then Result := True;
478end;
479
480procedure TByteMap.FlipHorz(Dst: TByteMap);
481var
482 i, j: Integer;
483 P1, P2: PByte;
484 tmp: Byte;
485 W, W2: Integer;
486begin
487 W := Width;
488 if (Dst = nil) or (Dst = Self) then
489 begin
490 { In-place flipping }
491 P1 := PByte(Bits);
492 P2 := P1;
493 Inc(P2, Width - 1);
494 W2 := Width shr 1;
495 for J := 0 to Height - 1 do
496 begin
497 for I := 0 to W2 - 1 do
498 begin
499 tmp := P1^;
500 P1^ := P2^;
501 P2^ := tmp;
502 Inc(P1);
503 Dec(P2);
504 end;
505 Inc(P1, W - W2);
506 Inc(P2, W + W2);
507 end;
508 Changed;
509 end
510 else
511 begin
512 { Flip to Dst }
513 Dst.BeginUpdate;
514 Dst.SetSize(W, Height);
515 P1 := PByte(Bits);
516 P2 := PByte(Dst.Bits);
517 Inc(P2, W - 1);
518 for J := 0 to Height - 1 do
519 begin
520 for I := 0 to W - 1 do
521 begin
522 P2^ := P1^;
523 Inc(P1);
524 Dec(P2);
525 end;
526 Inc(P2, W shl 1);
527 end;
528 Dst.EndUpdate;
529 Dst.Changed;
530 end;
531end;
532
533procedure TByteMap.FlipVert(Dst: TByteMap);
534var
535 J, J2: Integer;
536 Buffer: PByteArray;
537 P1, P2: PByte;
538begin
539 if (Dst = nil) or (Dst = Self) then
540 begin
541 { in-place }
542 J2 := Height - 1;
543 GetMem(Buffer, Width);
544 for J := 0 to Height div 2 - 1 do
545 begin
546 P1 := PByte(ScanLine[J]);
547 P2 := PByte(ScanLine[J2]);
548 Move(P1^, Buffer^, Width);
549 Move(P2^, P1^, Width);
550 Move(Buffer^, P2^, Width);
551 Dec(J2);
552 end;
553 FreeMem(Buffer);
554 Changed;
555 end
556 else
557 begin
558 Dst.SetSize(Width, Height);
559 J2 := Height - 1;
560 for J := 0 to Height - 1 do
561 begin
562 Move(ScanLine[J]^, Dst.ScanLine[J2]^, Width);
563 Dec(J2);
564 end;
565 Dst.Changed;
566 end;
567end;
568
569function TByteMap.GetScanline(Y: Integer): PByteArray;
570begin
571 Result := @FBits^[Y * Width];
572end;
573
574function TByteMap.GetValPtr(X, Y: Integer): PByte;
575begin
576 Result := @FBits^[X + Y * Width];
577end;
578
579function TByteMap.GetValue(X, Y: Integer): Byte;
580begin
581 Result := FBits^[X + Y * Width];
582end;
583
584procedure TByteMap.Multiply(Value: Byte);
585var
586 Index: Integer;
587begin
588 for Index := 0 to FWidth * FHeight - 1 do
589 FBits^[Index] := ((FBits^[Index] * Value + $80) shr 8);
590end;
591
592procedure TByteMap.Add(Value: Byte);
593var
594 Index: Integer;
595begin
596 for Index := 0 to FWidth * FHeight - 1 do
597 FBits^[Index] := Min(FBits^[Index] + Value, 255);
598end;
599
600procedure TByteMap.Sub(Value: Byte);
601var
602 Index: Integer;
603begin
604 for Index := 0 to FWidth * FHeight - 1 do
605 FBits^[Index] := Max(FBits^[Index] + Value, 0);
606end;
607
608procedure TByteMap.ReadFrom(Source: TCustomBitmap32; Conversion: TConversionType);
609var
610 W, H, I, N: Integer;
611 SrcC: PColor32;
612 SrcB, DstB: PByte;
613 Value: TColor32;
614begin
615 BeginUpdate;
616 try
617 SetSize(Source.Width, Source.Height);
618 if Empty then Exit;
619
620 W := Source.Width;
621 H := Source.Height;
622 N := W * H - 1;
623 SrcC := Source.PixelPtr[0, 0];
624 SrcB := Pointer(SrcC);
625 DstB := @FBits^;
626 case Conversion of
627
628 ctRed:
629 begin
630 Inc(SrcB, 2);
631 for I := 0 to N do
632 begin
633 DstB^ := SrcB^;
634 Inc(DstB);
635 Inc(SrcB, 4);
636 end;
637 end;
638
639 ctGreen:
640 begin
641 Inc(SrcB, 1);
642 for I := 0 to N do
643 begin
644 DstB^ := SrcB^;
645 Inc(DstB);
646 Inc(SrcB, 4);
647 end;
648 end;
649
650 ctBlue:
651 begin
652 for I := 0 to N do
653 begin
654 DstB^ := SrcB^;
655 Inc(DstB);
656 Inc(SrcB, 4);
657 end;
658 end;
659
660 ctAlpha:
661 begin
662 Inc(SrcB, 3);
663 for I := 0 to N do
664 begin
665 DstB^ := SrcB^;
666 Inc(DstB);
667 Inc(SrcB, 4);
668 end;
669 end;
670
671 ctUniformRGB:
672 begin
673 for I := 0 to N do
674 begin
675 Value := SrcC^;
676 Value := (Value and $00FF0000) shr 16 + (Value and $0000FF00) shr 8 +
677 (Value and $000000FF);
678 Value := Value div 3;
679 DstB^ := Value;
680 Inc(DstB);
681 Inc(SrcC);
682 end;
683 end;
684
685 ctWeightedRGB:
686 begin
687 for I := 0 to N do
688 begin
689 DstB^ := Intensity(SrcC^);
690 Inc(DstB);
691 Inc(SrcC);
692 end;
693 end;
694 end;
695 finally
696 EndUpdate;
697 Changed;
698 end;
699end;
700
701procedure TByteMap.Rotate180(Dst: TByteMap);
702var
703 Src: PByteArray;
704 S, D: PByte;
705 X, Y: Integer;
706 T: Byte;
707begin
708 if (Dst = nil) or (Dst = Self) then
709 begin
710 for Y := 0 to FHeight - 1 do
711 begin
712 Src := Scanline[Y];
713 for X := 0 to (FWidth div 2) - 1 do
714 begin
715 T := Src^[X];
716 Src^[X] := Src^[Width - 1 - X];
717 Src^[Width - 1 - X] := T;
718 end;
719 end;
720 end
721 else
722 begin
723 S := PByte(FBits);
724 D := PByte(@Dst.Bits[FHeight * FWidth - 1]);
725 for X := 0 to FHeight * FWidth - 1 do
726 begin
727 D^ := S^;
728 Dec(D);
729 Inc(S);
730 end;
731 end;
732end;
733
734procedure TByteMap.Rotate270(Dst: TByteMap);
735var
736 Src: PByteArray;
737 Current: PByte;
738 X, Y, W, H: Integer;
739begin
740 if (Dst = nil) or (Dst = Self) then
741 begin
742 W := FWidth;
743 H := FHeight;
744
745 // inplace replace
746 GetMem(Src, W * H);
747
748 // copy bits
749 Move(Bits^, Src^, W * H);
750
751 SetSize(H, W);
752
753 Current := PByte(Src);
754 for Y := 0 to H - 1 do
755 for X := 0 to W - 1 do
756 begin
757 Bits^[(W - 1 - X) * H + Y] := Current^;
758 Inc(Current);
759 end;
760
761 // dispose old data pointer
762 FreeMem(Src);
763 end
764 else
765 begin
766 // exchange dimensions
767 Dst.SetSize(Height, Width);
768
769 for Y := 0 to FHeight - 1 do
770 begin
771 Src := Scanline[Y];
772 for X := 0 to FWidth - 1 do
773 Dst.Bits^[X * FHeight + FHeight - 1 - Y] := Src^[X];
774 end;
775 end;
776end;
777
778procedure TByteMap.Rotate90(Dst: TByteMap);
779var
780 Src: PByteArray;
781 Current: PByte;
782 X, Y, W, H: Integer;
783begin
784 if (Dst = nil) or (Dst = Self) then
785 begin
786 W := FWidth;
787 H := FHeight;
788
789 // inplace replace
790 GetMem(Src, W * H);
791
792 // copy bits
793 Move(Bits^, Src^, W * H);
794
795 SetSize(H, W);
796
797 Current := PByte(Src);
798 for Y := 0 to H - 1 do
799 for X := 0 to W - 1 do
800 begin
801 Bits^[X * H + (H - 1 - Y)] := Current^;
802 Inc(Current);
803 end;
804
805 // dispose old data pointer
806 FreeMem(Src);
807 end
808 else
809 begin
810 // exchange dimensions
811 Dst.SetSize(Height, Width);
812
813 for Y := 0 to FHeight - 1 do
814 begin
815 Src := Scanline[Y];
816 for X := 0 to FWidth - 1 do
817 Dst.Bits^[(FWidth - 1 - X) * FHeight + Y] := Src^[X];
818 end;
819 end;
820end;
821
822procedure TByteMap.SetValue(X, Y: Integer; Value: Byte);
823begin
824 FBits^[X + Y * Width] := Value;
825end;
826
827procedure TByteMap.WriteTo(Dest: TCustomBitmap32; Conversion: TConversionType);
828var
829 W, H, I, N: Integer;
830 DstC: PColor32;
831 DstB, SrcB: PByte;
832 Resized: Boolean;
833begin
834 Dest.BeginUpdate;
835 Resized := False;
836 try
837 Resized := Dest.SetSize(Width, Height);
838 if Empty then Exit;
839
840 W := Width;
841 H := Height;
842 N := W * H - 1;
843 DstC := Dest.PixelPtr[0, 0];
844 DstB := Pointer(DstC);
845 SrcB := @FBits^;
846 case Conversion of
847
848 ctRed:
849 begin
850 Inc(DstB, 2);
851 for I := 0 to N do
852 begin
853 DstB^ := SrcB^;
854 Inc(DstB, 4);
855 Inc(SrcB);
856 end;
857 end;
858
859 ctGreen:
860 begin
861 Inc(DstB, 1);
862 for I := 0 to N do
863 begin
864 DstB^ := SrcB^;
865 Inc(DstB, 4);
866 Inc(SrcB);
867 end;
868 end;
869
870 ctBlue:
871 begin
872 for I := 0 to N do
873 begin
874 DstB^ := SrcB^;
875 Inc(DstB, 4);
876 Inc(SrcB);
877 end;
878 end;
879
880 ctAlpha:
881 begin
882 Inc(DstB, 3);
883 for I := 0 to N do
884 begin
885 DstB^ := SrcB^;
886 Inc(DstB, 4);
887 Inc(SrcB);
888 end;
889 end;
890
891 ctUniformRGB, ctWeightedRGB:
892 begin
893 for I := 0 to N do
894 begin
895 DstC^ := Gray32(SrcB^);
896 Inc(DstC);
897 Inc(SrcB);
898 end;
899 end;
900 end;
901 finally
902 Dest.EndUpdate;
903 Dest.Changed;
904 if Resized then Dest.Resized;
905 end;
906end;
907
908procedure TByteMap.WriteTo(Dest: TCustomBitmap32; const Palette: TPalette32);
909var
910 W, H, I, N: Integer;
911 DstC: PColor32;
912 SrcB: PByte;
913begin
914 Dest.BeginUpdate;
915 try
916 Dest.SetSize(Width, Height);
917 if Empty then Exit;
918
919 W := Width;
920 H := Height;
921 N := W * H - 1;
922 DstC := Dest.PixelPtr[0, 0];
923 SrcB := @FBits^;
924
925 for I := 0 to N do
926 begin
927 DstC^ := Palette[SrcB^];
928 Inc(DstC);
929 Inc(SrcB);
930 end;
931 finally
932 Dest.EndUpdate;
933 Dest.Changed;
934 end;
935end;
936
937procedure TByteMap.DrawTo(Dest: TCustomBitmap32; X, Y: Integer; Color: TColor32);
938var
939 ClipRect: TRect;
940 IX, IY: Integer;
941 RGB: Cardinal;
942 NewColor: TColor32;
943 ScnLn: PColor32Array;
944 ByteLine: PByteArray;
945 Alpha: Byte;
946begin
947 with ClipRect do
948 begin
949 Left := X;
950 if Left < 0 then
951 Left := 0;
952 Top := Y;
953 if Top < 0 then
954 Top := 0;
955 Right := X + Self.Width;
956 if Right > Self.Width then
957 Right := Self.Width;
958 Bottom := Y + Self.Height;
959 if Bottom > Self.Height then
960 Bottom := Self.Height;
961
962 // split RGB and alpha
963 RGB := Color and $FFFFFF;
964 Alpha := Color shr 24;
965
966 // blend scanlines
967 for IY := Top to Bottom - 1 do
968 begin
969 ScnLn := Dest.ScanLine[IY];
970 ByteLine := Self.ScanLine[IY - Y];
971 for IX := Left to Right - 1 do
972 begin
973 NewColor := (((ByteLine^[IX - X] * Alpha) shl 16) and $FF000000) or RGB;
974 MergeMem(NewColor, ScnLn^[IX]);
975 end;
976 end;
977 EMMS;
978 end;
979end;
980
981procedure TByteMap.DrawTo(Dest: TCustomBitmap32; Rect: TRect; Color: TColor32);
982var
983 ClipRect: TRect;
984 IX, IY: Integer;
985 RGB: Cardinal;
986 NewColor: TColor32;
987 ScnLn: PColor32Array;
988 ByteLine: PByteArray;
989 Alpha: Byte;
990begin
991 with ClipRect do
992 begin
993 Left := Rect.Left;
994 if Left < 0 then
995 Left := 0;
996 Top := Rect.Top;
997 if Top < 0 then
998 Top := 0;
999 Right := Math.Min(Rect.Left + Self.Width, Rect.Right);
1000 Bottom := Math.Min(Rect.Top + Self.Height, Rect.Bottom);
1001
1002 // split RGB and alpha
1003 RGB := Color and $FFFFFF;
1004 Alpha := Color shr 24;
1005
1006 // blend scanlines
1007 for IY := Top to Bottom - 1 do
1008 begin
1009 ScnLn := Dest.ScanLine[IY];
1010 ByteLine := Self.ScanLine[IY - Rect.Top];
1011 for IX := Left to Right - 1 do
1012 begin
1013 NewColor := (((ByteLine^[IX - Rect.Left] * Alpha) shl 16) and $FF000000) or RGB;
1014 MergeMem(NewColor, ScnLn^[IX]);
1015 end;
1016 end;
1017 EMMS;
1018 end;
1019end;
1020
1021
1022{ TWordMap }
1023
1024constructor TWordMap.Create;
1025begin
1026 FBits := nil;
1027 inherited Create;
1028end;
1029
1030destructor TWordMap.Destroy;
1031begin
1032 FreeMem(FBits);
1033 inherited;
1034end;
1035
1036procedure TWordMap.ChangeSize(var Width, Height: Integer; NewWidth,
1037 NewHeight: Integer);
1038begin
1039 ReallocMem(FBits, NewWidth * NewHeight * SizeOf(Word));
1040 Width := NewWidth;
1041 Height := NewHeight;
1042end;
1043
1044procedure TWordMap.Clear(FillValue: Word);
1045begin
1046 FillWord(FBits^, Width * Height, FillValue);
1047 Changed;
1048end;
1049
1050procedure TWordMap.Assign(Source: TPersistent);
1051begin
1052 BeginUpdate;
1053 try
1054 if Source is TWordMap then
1055 begin
1056 inherited SetSize(TWordMap(Source).Width, TWordMap(Source).Height);
1057 Move(TWordMap(Source).Bits[0], Bits[0], Width * Height * SizeOf(Word));
1058 end
1059 //else if Source is TBitmap32 then
1060 // ReadFrom(TBitmap32(Source), ctWeightedRGB)
1061 else
1062 inherited;
1063 finally
1064 EndUpdate;
1065 Changed;
1066 end;
1067end;
1068
1069function TWordMap.Empty: Boolean;
1070begin
1071 Result := not Assigned(FBits);
1072end;
1073
1074function TWordMap.GetScanline(Y: Integer): PWordArray;
1075begin
1076 Result := @FBits^[Y * Width];
1077end;
1078
1079function TWordMap.GetValPtr(X, Y: Integer): PWord;
1080begin
1081 Result := @FBits^[X + Y * Width];
1082end;
1083
1084function TWordMap.GetValue(X, Y: Integer): Word;
1085begin
1086 Result := FBits^[X + Y * Width];
1087end;
1088
1089procedure TWordMap.SetValue(X, Y: Integer; const Value: Word);
1090begin
1091 FBits^[X + Y * Width] := Value;
1092end;
1093
1094
1095{ TIntegerMap }
1096
1097constructor TIntegerMap.Create;
1098begin
1099 FBits := nil;
1100 inherited Create;
1101end;
1102
1103destructor TIntegerMap.Destroy;
1104begin
1105 FreeMem(FBits);
1106 inherited;
1107end;
1108
1109procedure TIntegerMap.ChangeSize(var Width, Height: Integer; NewWidth,
1110 NewHeight: Integer);
1111begin
1112 ReallocMem(FBits, NewWidth * NewHeight * SizeOf(Integer));
1113 Width := NewWidth;
1114 Height := NewHeight;
1115end;
1116
1117procedure TIntegerMap.Clear(FillValue: Integer);
1118begin
1119 FillLongword(FBits^, Width * Height, FillValue);
1120 Changed;
1121end;
1122
1123procedure TIntegerMap.Assign(Source: TPersistent);
1124begin
1125 BeginUpdate;
1126 try
1127 if Source is TIntegerMap then
1128 begin
1129 inherited SetSize(TIntegerMap(Source).Width, TIntegerMap(Source).Height);
1130 Move(TIntegerMap(Source).Bits[0], Bits[0], Width * Height * SizeOf(Integer));
1131 end
1132 //else if Source is TBitmap32 then
1133 // ReadFrom(TBitmap32(Source), ctWeightedRGB)
1134 else
1135 inherited;
1136 finally
1137 EndUpdate;
1138 Changed;
1139 end;
1140end;
1141
1142function TIntegerMap.Empty: Boolean;
1143begin
1144 Result := not Assigned(FBits);
1145end;
1146
1147function TIntegerMap.GetScanline(Y: Integer): PIntegerArray;
1148begin
1149 Result := @FBits^[Y * Width];
1150end;
1151
1152function TIntegerMap.GetValPtr(X, Y: Integer): PInteger;
1153begin
1154 Result := @FBits^[X + Y * Width];
1155end;
1156
1157function TIntegerMap.GetValue(X, Y: Integer): Integer;
1158begin
1159 Result := FBits^[X + Y * Width];
1160end;
1161
1162procedure TIntegerMap.SetValue(X, Y: Integer; const Value: Integer);
1163begin
1164 FBits^[X + Y * Width] := Value;
1165end;
1166
1167
1168{ TCardinalMap }
1169
1170constructor TCardinalMap.Create;
1171begin
1172 FBits := nil;
1173 inherited Create;
1174end;
1175
1176destructor TCardinalMap.Destroy;
1177begin
1178 FreeMem(FBits);
1179 inherited;
1180end;
1181
1182procedure TCardinalMap.Assign(Source: TPersistent);
1183begin
1184 BeginUpdate;
1185 try
1186 if Source is TCardinalMap then
1187 begin
1188 inherited SetSize(TCardinalMap(Source).Width, TCardinalMap(Source).Height);
1189 Move(TCardinalMap(Source).Bits[0], Bits[0], Width * Height * SizeOf(Cardinal));
1190 end
1191 //else if Source is TBitmap32 then
1192 // ReadFrom(TBitmap32(Source), ctWeightedRGB)
1193 else
1194 inherited;
1195 finally
1196 EndUpdate;
1197 Changed;
1198 end;
1199end;
1200
1201procedure TCardinalMap.ChangeSize(var Width, Height: Integer; NewWidth,
1202 NewHeight: Integer);
1203begin
1204 ReallocMem(FBits, NewWidth * NewHeight * SizeOf(Cardinal));
1205 Width := NewWidth;
1206 Height := NewHeight;
1207end;
1208
1209procedure TCardinalMap.Clear(FillValue: Cardinal);
1210begin
1211 FillLongword(FBits^, Width * Height, FillValue);
1212 Changed;
1213end;
1214
1215function TCardinalMap.Empty: Boolean;
1216begin
1217 Result := not Assigned(FBits);
1218end;
1219
1220function TCardinalMap.GetScanline(Y: Integer): PCardinalArray;
1221begin
1222 Result := @FBits^[Y * Width];
1223end;
1224
1225function TCardinalMap.GetValPtr(X, Y: Cardinal): PCardinal;
1226begin
1227 Result := @FBits^[X + Y * Cardinal(Width)];
1228end;
1229
1230function TCardinalMap.GetValue(X, Y: Cardinal): Cardinal;
1231begin
1232 Result := FBits^[X + Y * Cardinal(Width)];
1233end;
1234
1235procedure TCardinalMap.SetValue(X, Y: Cardinal; const Value: Cardinal);
1236begin
1237 FBits^[X + Y * Cardinal(Width)] := Value;
1238end;
1239
1240
1241{ TFloatMap }
1242
1243constructor TFloatMap.Create;
1244begin
1245 FBits := nil;
1246 inherited Create;
1247end;
1248
1249destructor TFloatMap.Destroy;
1250begin
1251 FreeMem(FBits);
1252 inherited;
1253end;
1254
1255procedure TFloatMap.Assign(Source: TPersistent);
1256begin
1257 BeginUpdate;
1258 try
1259 if Source is TFloatMap then
1260 begin
1261 inherited SetSize(TFloatMap(Source).Width, TFloatMap(Source).Height);
1262 Move(TFloatMap(Source).Bits[0], Bits[0], Width * Height * SizeOf(TFloat));
1263 end
1264 //else if Source is TBitmap32 then
1265 // ReadFrom(TBitmap32(Source), ctWeightedRGB)
1266 else
1267 inherited;
1268 finally
1269 EndUpdate;
1270 Changed;
1271 end;
1272end;
1273
1274procedure TFloatMap.ChangeSize(var Width, Height: Integer; NewWidth,
1275 NewHeight: Integer);
1276begin
1277 ReallocMem(FBits, NewWidth * NewHeight * SizeOf(TFloat));
1278 Width := NewWidth;
1279 Height := NewHeight;
1280end;
1281
1282procedure TFloatMap.Clear;
1283begin
1284 FillChar(FBits^, Width * Height * SizeOf(TFloat), 0);
1285 Changed;
1286end;
1287
1288procedure TFloatMap.Clear(FillValue: TFloat);
1289var
1290 Index: Integer;
1291begin
1292 for Index := 0 to Width * Height - 1 do
1293 FBits^[Index] := FillValue;
1294 Changed;
1295end;
1296
1297function TFloatMap.Empty: Boolean;
1298begin
1299 Result := not Assigned(FBits);
1300end;
1301
1302function TFloatMap.GetScanline(Y: Integer): PFloatArray;
1303begin
1304 Result := @FBits^[Y * Width];
1305end;
1306
1307function TFloatMap.GetValPtr(X, Y: Integer): GR32.PFloat;
1308begin
1309 Result := @FBits^[X + Y * Width];
1310end;
1311
1312function TFloatMap.GetValue(X, Y: Integer): TFloat;
1313begin
1314 Result := FBits^[X + Y * Width];
1315end;
1316
1317procedure TFloatMap.SetValue(X, Y: Integer; const Value: TFloat);
1318begin
1319 FBits^[X + Y * Width] := Value;
1320end;
1321
1322
1323{$IFDEF COMPILER2010}
1324
1325{ TGenericMap<T> }
1326
1327constructor TGenericMap<T>.Create;
1328begin
1329 FBits := nil;
1330 inherited Create;
1331end;
1332
1333destructor TGenericMap<T>.Destroy;
1334begin
1335 FreeMem(FBits);
1336 inherited;
1337end;
1338
1339procedure TGenericMap<T>.Assign(Source: TPersistent);
1340begin
1341 BeginUpdate;
1342 try
1343(*
1344 if Source is TFloatMap then
1345 begin
1346 inherited SetSize(TFloatMap(Source).Width, TFloatMap(Source).Height);
1347 Move(TFloatMap(Source).Bits[0], Bits[0], Width * Height * SizeOf(TFloat));
1348 end
1349 //else if Source is TBitmap32 then
1350 // ReadFrom(TBitmap32(Source), ctWeightedRGB)
1351 else
1352 inherited;
1353*)
1354 finally
1355 EndUpdate;
1356 Changed;
1357 end;
1358end;
1359
1360procedure TGenericMap<T>.ChangeSize(var Width, Height: Integer; NewWidth,
1361 NewHeight: Integer);
1362begin
1363 ReallocMem(FBits, NewWidth * NewHeight * SizeOf(T));
1364 Width := NewWidth;
1365 Height := NewHeight;
1366end;
1367
1368procedure TGenericMap<T>.Clear(FillValue: T);
1369var
1370 Index: Integer;
1371begin
1372 for Index := 0 to Width * Height - 1 do
1373 Move(FillValue, PByte(FBits)[Index], SizeOf(T));
1374 Changed;
1375end;
1376
1377procedure TGenericMap<T>.Clear;
1378begin
1379 FillChar(FBits^, Width * Height * SizeOf(T), 0);
1380 Changed;
1381end;
1382
1383function TGenericMap<T>.Empty: Boolean;
1384begin
1385 Result := not Assigned(FBits);
1386end;
1387
1388function TGenericMap<T>.GetValue(X, Y: Integer): T;
1389begin
1390 Move(PByte(FBits)[(X + Y * Width) * SizeOf(T)], Result, SizeOf(T));
1391end;
1392
1393procedure TGenericMap<T>.SetValue(X, Y: Integer; const Value: T);
1394begin
1395 Move(Value, PByte(FBits)[(X + Y * Width) * SizeOf(T)], SizeOf(T));
1396end;
1397
1398{$ENDIF}
1399
1400end.
Note: See TracBrowser for help on using the repository browser.