Changeset 35 for trunk/Packages


Ignore:
Timestamp:
May 4, 2018, 12:56:52 PM (7 years ago)
Author:
chronos
Message:
  • Fixed: Do not allocate big temp image for drawing on screen of zoomed out image.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Packages/FastGraphics/UGGraphics.pas

    r34 r35  
    5151      TGConvertFromColor = function (Color: TColor): TGColor of object;
    5252      TGGetColor = function (Position: TPoint): TGColor of object;
     53      PGColor = ^TGColor;
    5354  protected
    5455    FData: PByte;
    5556    FSize: TPoint;
    5657    FCanvas: TGCanvas<TGColor>;
     58    FBytesPerLine: Integer;
     59    FBytesPerPixel: Integer;
    5760    function GetPixel(X, Y: Integer): TGColor; virtual;
    5861    function GetSize: TPoint; virtual;
     
    6669    procedure PaintToCanvas(Canvas: TCanvas; ColorConvertFunc: TGConvertColor); overload;
    6770    procedure PaintToCanvas(Canvas: TCanvas; Rect: TRect; ColorConvertFunc: TGConvertColor); overload;
    68     procedure PaintToBitmap(Bitmap: TBitmap; Rect: TRect; ColorConvertFunc: TGConvertColor);
     71    procedure PaintToBitmap(Bitmap: TBitmap; Pos: TPoint; ColorConvertFunc: TGConvertColor); overload;
     72    procedure PaintToBitmap(Bitmap: TBitmap; Rect: TRect; ColorConvertFunc: TGConvertColor); overload;
    6973    procedure LoadFromCanvas(Canvas: TCanvas; ColorConvertFunc: TGConvertFromColor); overload;
    7074    procedure LoadFromBitmap(Bitmap: TBitmap; ColorConvertFunc: TGConvertFromColor);
     
    96100  end;
    97101
     102  { TPixelPointer }
     103
     104  TPixelPointer = record
     105    Base: Pointer;
     106    Pixel: Pointer;
     107    Line: Pointer;
     108    BytesPerPixel: Integer;
     109    BytesPerLine: Integer;
     110    procedure NextLine; inline; // Move pointer to start of new base line
     111    procedure NextPixel; inline; // Move pointer to next pixel
     112    procedure SetXY(X, Y: Integer); inline; // Set pixel position relative to base
     113    procedure SetX(X: Integer); inline; // Set horizontal pixel position relative to base
     114    procedure Init(Bitmap: TRasterImage; BaseX: Integer = 0; BaseY: Integer = 0); inline; overload;
     115    procedure Init(Base: Pointer; BytesPerLine, BytesPerPixel: Integer; BaseX: Integer = 0; BaseY: Integer = 0); inline; overload;
     116 end;
     117
    98118
    99119implementation
    100120
     121{ TPixelPointer }
     122
     123procedure TPixelPointer.NextLine; inline;
     124begin
     125  Line := Pointer(Line) + BytesPerLine;
     126  Pixel := Line;
     127end;
     128
     129procedure TPixelPointer.NextPixel; inline;
     130begin
     131  Pixel := Pointer(Pixel) + BytesPerPixel;
     132end;
     133
     134procedure TPixelPointer.SetXY(X, Y: integer); inline;
     135begin
     136  Line := Pointer(Base) + Y * BytesPerLine;
     137  SetX(X);
     138end;
     139
     140procedure TPixelPointer.SetX(X: Integer); inline;
     141begin
     142  Pixel := Pointer(Line) + X * BytesPerPixel;
     143end;
     144
     145procedure TPixelPointer.Init(Bitmap: TRasterImage; BaseX: Integer = 0;
     146  BaseY: Integer = 0); inline;
     147begin
     148  Init(Bitmap.RawImage.Data, Bitmap.RawImage.Description.BytesPerLine, Bitmap.RawImage.Description.BitsPerPixel shr 3, BaseX, BaseY);
     149end;
     150
     151procedure TPixelPointer.Init(Base: Pointer; BytesPerLine, BytesPerPixel: Integer; BaseX: Integer = 0; BaseY: Integer = 0); inline; overload;
     152begin
     153  Self.BytesPerLine := BytesPerLine;
     154  Self.BytesPerPixel := BytesPerPixel;
     155  Self.Base := Pointer(Base + BaseX * BytesPerPixel + BaseY * BytesPerLine);
     156  SetXY(0, 0);
     157end;
     158
    101159{ TGPixmap }
    102160
     
    104162begin
    105163  CheckLimits(X, Y);
    106   Move(PByte(FData + (X + Y * FSize.X) * SizeOf(TGColor))^, Result, SizeOf(TGColor));
     164  Move(PByte(FData + X * FBytesPerPixel + Y * FBytesPerLine)^, Result, SizeOf(TGColor));
    107165end;
    108166
     
    110168begin
    111169  CheckLimits(X, Y);
    112   Move(AValue, PByte(FData + (X + Y * FSize.X) * SizeOf(TGColor))^, SizeOf(TGColor));
     170  Move(AValue, PByte(FData + X * FBytesPerPixel + Y * FBytesPerLine)^, SizeOf(TGColor));
    113171end;
    114172
     
    122180  if (FSize.X <> AValue.X) and (FSize.Y <> AValue.Y) then begin
    123181    FSize := AValue;
    124     ReAllocMem(FData, FSize.X * FSize.Y * SizeOf(TGColor));
     182    FBytesPerPixel := SizeOf(TGColor);
     183    FBytesPerLine := AValue.X * FBytesPerPixel;
     184    ReAllocMem(FData, FSize.X * FBytesPerLine);
    125185  end;
    126186end;
     
    128188constructor TGPixmap<TGColor>.Create;
    129189begin
     190  Size := Point(0, 0);
    130191  FCanvas := TGCanvas<TGColor>.Create;
    131192  FCanvas.Bitmap := Self;
     
    195256end;
    196257
     258procedure TGPixmap<TGColor>.PaintToBitmap(Bitmap: TBitmap; Pos: TPoint;
     259  ColorConvertFunc: TGConvertColor);
     260var
     261  X, Y: Integer;
     262  DstPtr: TPixelPointer;
     263  SrcPtr: TPixelPointer;
     264begin
     265  try
     266    Bitmap.BeginUpdate(False);
     267    DstPtr.Init(Bitmap);
     268    SrcPtr.Init(FData, FBytesPerLine, FBytesPerPixel, Pos.X, Pos.Y);
     269    for Y := 0 to Bitmap.Height - 1 do begin
     270      for X := 0 to Bitmap.Width - 1 do begin
     271        if ((X + Pos.X) >= 0) and ((X + Pos.X) < FSize.X) and
     272        ((Y + Pos.Y) >= 0) and ((Y + Pos.Y) < FSize.Y) then begin
     273          PInteger(DstPtr.Pixel)^ := ColorConvertFunc(PGColor(SrcPtr.Pixel)^);
     274        end;
     275        DstPtr.NextPixel;
     276        SrcPtr.NextPixel;
     277      end;
     278      DstPtr.NextLine;
     279      SrcPtr.NextLine;
     280    end;
     281  finally
     282    Bitmap.EndUpdate(False);
     283  end;
     284end;
     285
    197286procedure TGPixmap<TGColor>.PaintToBitmap(Bitmap: TBitmap; Rect: TRect;
    198287  ColorConvertFunc: TGConvertColor);
    199288var
    200289  X, Y: Integer;
    201   PixelPtr: PInteger;
    202   PixelPtrMax: PInteger;
    203   PixelPtrMin: PInteger;
    204   PixelRowPtr: PInteger;
    205   RawImage: TRawImage;
    206   BytePerPixel: Integer;
     290  DstPtr: TPixelPointer;
     291  ZoomX: Single;
     292  ZoomY: Single;
     293  SrcX: Integer;
     294  SrcY: Integer;
    207295begin
    208296  try
    209297    Bitmap.BeginUpdate(False);
    210     RawImage := Bitmap.RawImage;
    211     PixelRowPtr := PInteger(RawImage.Data);
    212     BytePerPixel := RawImage.Description.BitsPerPixel div 8;
    213     PixelPtrMin := PixelRowPtr;
    214     PixelPtrMax := PixelRowPtr + RawImage.Description.Width * RawImage.Description.Height * BytePerPixel;
     298    DstPtr.Init(Bitmap);
     299    ZoomX := Bitmap.Width / (Rect.Right - Rect.Left);
     300    ZoomY := Bitmap.Height / (Rect.Bottom - Rect.Top);
    215301    for Y := 0 to Bitmap.Height - 1 do begin
    216       PixelPtr := PixelRowPtr;
     302      SrcY := Trunc(Y / ZoomY + Rect.Top);
    217303      for X := 0 to Bitmap.Width - 1 do begin
    218         if ((X + Rect.Left) >= 0) and ((X + Rect.Left) < FSize.X) and
    219         ((Y + Rect.Top) >= 0) and ((Y + Rect.Top) < FSize.Y) and
    220         (PixelPtr < PixelPtrMax) and (PixelPtr >= PixelPtrMin) then begin
    221           PixelPtr^ := ColorConvertFunc(Pixels[X + Rect.Left, Y + Rect.Top]);
     304        SrcX := Trunc(X / ZoomX + Rect.Left);
     305        if (SrcX >= 0) and (SrcX < FSize.X) and
     306        (SrcY >= 0) and (SrcY < FSize.Y) then begin
     307          PInteger(DstPtr.Pixel)^ := ColorConvertFunc(Pixels[SrcX, SrcY]);
    222308        end;
    223         Inc(PByte(PixelPtr), BytePerPixel);
     309        DstPtr.NextPixel;
    224310      end;
    225       Inc(PByte(PixelRowPtr), RawImage.Description.BytesPerLine);
     311      DstPtr.NextLine;
    226312    end;
    227313  finally
     
    248334var
    249335  X, Y: Integer;
    250   PixelPtr: PInteger;
    251   PixelPtrMax: PInteger;
    252   PixelRowPtr: PInteger;
    253   P: TPixelFormat;
    254   RawImage: TRawImage;
    255   BytePerPixel: Integer;
     336  SrcPtr: TPixelPointer;
     337  DstPtr: TPixelPointer;
    256338begin
    257339  try
    258340    Bitmap.BeginUpdate(False);
    259     RawImage := Bitmap.RawImage;
    260     PixelRowPtr := PInteger(RawImage.Data);
    261     BytePerPixel := RawImage.Description.BitsPerPixel div 8;
    262     PixelPtrMax := PixelRowPtr + RawImage.Description.Width * RawImage.Description.Height * BytePerPixel;
     341    SrcPtr.Init(Bitmap);
     342    DstPtr.Init(FData, FBytesPerLine, FBytesPerPixel);
    263343    for Y := 0 to FSize.Y - 1 do begin
    264       PixelPtr := PixelRowPtr;
    265344      for X := 0 to FSize.X - 1 do begin
    266         if (X >= 0) and (X < FSize.X) and (Y >= 0) and (Y < FSize.Y) and (PixelPtr < PixelPtrMax) then
    267           Pixels[X, Y] := ColorConvertFunc(PixelPtr^);
    268         Inc(PByte(PixelPtr), BytePerPixel);
     345        if (X >= 0) and (X < FSize.X) and (Y >= 0) and (Y < FSize.Y) then
     346          PInteger(DstPtr.Pixel)^ := ColorConvertFunc(PInteger(SrcPtr.Pixel)^);
     347        SrcPtr.NextPixel;
     348        DstPtr.NextPixel;
    269349      end;
    270       Inc(PByte(PixelRowPtr), RawImage.Description.BytesPerLine);
     350      SrcPtr.NextLine;
     351      DstPtr.NextLine;
    271352    end;
    272353  finally
     
    277358function TGPixmap<TGColor>.GetDataSize: Int64;
    278359begin
    279   Result := FSize.X * FSize.Y * SizeOf(TGColor);
     360  Result := FSize.Y * FBytesPerLine;
    280361end;
    281362
Note: See TracChangeset for help on using the changeset viewer.