Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How To Zoom with keeping aspect ratio correctly

Well this is my goal. Use left mouse button to scroll the image, right mouse button to choose zoom rectangle and doubleclick to restore full zoom.

I have currently tired, so far found its NOT to do with the way i load the images or display the image but something with how it paints. The on-screen image always fills the control's client area regardless of the shape of the form or the source image, so the aspect ratio cannot possibly be preserved. I am not sure how to change this or keep the aspect ratio. Thus giving me a clean nice picture.

I am posting the whole code for my ZImage unit Though i think the problem is either in the Zimage.paint or Zimage.mouseup But figured if you needed to see a function inside one of those it would help to have it all posted.

unit ZImage;

interface

uses
  Windows, Messages, SysUtils,jpeg, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls;

type
  TZImage = class(TGraphicControl)
  private
    FBitmap        : Tbitmap;
    PicRect        : TRect;
    ShowRect       : TRect;
    FShowBorder    : boolean;
    FBorderWidth   : integer;
    FForceRepaint  : boolean;
    FMouse         : (mNone, mDrag, mZoom);
    FProportional  : boolean;
    FDblClkEnable  : boolean;
    FLeft        :integer;
    FRight        :integer;
    FTop             :integer;
    FBottom             :integer;
    startx, starty,
    oldx, oldy     : integer;
    procedure SetShowBorder(s:boolean);
    procedure SetBitmap(b:TBitmap);
    procedure SetBorderWidth(w:integer);
    procedure SetProportional(b:boolean);
  protected
    procedure Paint; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
                        X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
              X, Y: Integer); override;
  public
    constructor Create(AOwner:TComponent); override;
    destructor Destroy; override;
    procedure DblClick; override;
  published
  procedure zoom(Endleft,EndRight,EndTop,EndBottom:integer);
    property ValueLeft    : integer read FLeft write FLeft;
    property ValueRight    : Integer read FRight write FRight;
    Property ValueTop         : Integer read FTop write FTop;
    Property ValueBottom         : Integer read FBottom write FBottom;
    property ShowBorder : boolean
                 read FShowBorder
                 write SetShowBorder default true;
    property KeepAspect : boolean
                 read FProportional
                 write SetProportional default true;
    property Bitmap : TBitmap
                 read FBitmap
                 write Setbitmap;
    property BorderWidth : integer
                 read FBorderWidth
                 write SetBorderWidth default 7;
    property ForceRepaint : boolean
                 read FForceRepaint
                 write FForceRepaint default true;
    property DblClkEnable : boolean
                 read FDblClkEnable
                 write FDblClkEnable default False;
    property Align;
    property Width;
    property Height;
    property Top;
    property Left;
    property Visible;
    property Hint;
    property ShowHint;
  end;

procedure Register;

implementation

 //This is the basic create options.
constructor TZImage.Create(AOwner:TComponent);
begin
   inherited;
   FShowBorder:=True;
   FBorderWidth:=7;
   FMouse:=mNone;
   FForceRepaint:=true;    //was true
   FDblClkEnable:=False;
   FProportional:=true;   //was true
   Width:=100; Height:=100;
   FBitmap:=Tbitmap.Create;
   FBitmap.Width:=width;
   FBitmap.height:=Height;
   ControlStyle:=ControlStyle+[csOpaque];
   autosize:= false;
   //Scaled:=false;
end;


//basic destroy frees the FBitmap
destructor TZImage.Destroy;
begin
   FBitmap.Free;
   inherited;
end;

//This was a custom zoom i was using to give the automated zoom effect
procedure TZimage.zoom(Endleft,EndRight,EndTop,EndBottom:integer);
begin

   while ((Endbottom <> picrect.bottom) or (Endtop <> picrect.top)) or ((endleft <> picrect.left) or (endright <> picrect.right)) do
     begin
       if picrect.left > endleft then
            picrect.left := picrect.left -1;
       if picrect.left < endleft  then  //starting
            picrect.left := picrect.left +1;

       if picrect.right > endright then   //starting
            picrect.right := picrect.right -1;
       if picrect.right < endright  then
            picrect.right := picrect.right +1;

       if picrect.top > endtop then
            picrect.top := picrect.top -1;
       if picrect.top < endtop then //starting
            picrect.top := picrect.top +1;

       if picrect.bottom > endbottom then  //starting
            picrect.bottom := picrect.bottom -1;
       if picrect.bottom < endbottom  then
           picrect.bottom := picrect.bottom +1;
       self.refresh;
     end;

end;

//this is the custom paint I know if i put
//Canvas.Draw(0,0,FBitmap);  as the methond it displays
//perfect but the zoom option is gone of course and
//i need the Zoom.
procedure TZImage.Paint;
var buf:TBitmap;
    coef,asps,aspp:Double;
    sz,a : integer;
begin

   buf:=TBitmap.Create;
   buf.Width:=Width;
   buf.Height:=Height;
   if not FShowBorder
     then ShowRect:=ClientRect
     else ShowRect:=Rect(ClientRect.Left,ClientRect.Top,
                         ClientRect.Right-FBorderWidth,
                         ClientRect.Bottom-FBorderWidth);
   ShowRect:=ClientRect;
   with PicRect do begin
    if Right=0 then Right:=FBitmap.Width;
    if Bottom=0 then Bottom:=FBitmap.Height;
   end;
   buf.Canvas.CopyMode:=cmSrcCopy;
   buf.Canvas.CopyRect(ShowRect,FBitmap.Canvas,PicRect);
   Canvas.CopyMode:=cmSrcCopy;
   Canvas.Draw(0,0,buf);
   buf.Free;
end;

procedure TZImage.MouseDown(Button: TMouseButton; Shift: TShiftState;
                            X, Y: Integer);
begin

//   if mbLeft<>Button then Exit;
   if not PtInRect(ShowRect,Point(X,Y)) and
      not PtInRect(Rect(ShowRect.Right,ShowRect.Bottom,
                        Width,Height),Point(X,Y)) then Exit;
   if PtInRect(Rect(ShowRect.Right,ShowRect.Bottom,
                    Width,Height),Point(X,Y)) then begin
      DblClick;
      Exit;
   end;
   //here click is in the picture area only
   startx:=x; oldx:=x;
   starty:=y; oldy:=y;
   if mbRight=Button then begin
      MouseCapture:=True;
      FMouse:=mZoom;
      Canvas.Pen.Mode:=pmNot;
   end else begin
      FMouse:=mDrag;
      Screen.Cursor:=crHandPoint;
   end;
end;



function Min(a,b:integer):integer;
begin
   if a<b then Result:=a else Result:=b;
end;
function Max(a,b:integer):integer;
begin
   if a<b then Result:=b else Result:=a;
end;



procedure TZImage.MouseMove(Shift: TShiftState; X, Y: Integer);
var d,s:integer;
    coef:Double;
begin
    if FMouse=mNone then Exit;
    if FMouse=mZoom then begin
       Canvas.DrawFocusRect(Rect(Min(startx,oldx),Min(starty,oldy),Max(startx,oldx),Max(starty,oldy)));
       oldx:=x; oldy:=y;
       Canvas.DrawFocusRect(Rect(Min(startx,oldx),Min(starty,oldy),Max(startx,oldx),Max(starty,oldy)));
    end;
    if FMouse=mDrag then begin
//horizontal movement
       coef:=(PicRect.Right-PicRect.Left)/(ShowRect.Right-ShowRect.Left);
       d:=Round(coef*(x-oldx));
       s:=PicRect.Right-PicRect.Left;
       if d>0 then begin
          if PicRect.Left>=d then begin
            PicRect.Left:=PicRect.Left-d;
            PicRect.Right:=PicRect.Right-d;
          end else begin
            PicRect.Left:=0;
            PicRect.Right:=PicRect.Left+s;
          end;
       end;
       if d<0 then begin
          if PicRect.Right<FBitmap.Width+d then begin
            PicRect.Left:=PicRect.Left-d;
            PicRect.Right:=PicRect.Right-d;
          end else begin
            PicRect.Right:=FBitmap.Width;
            PicRect.Left:=PicRect.Right-s;
          end;
       end;

//vertical movement
       coef:=(PicRect.Bottom-PicRect.Top)/(ShowRect.Bottom-ShowRect.Top);
       d:=Round(coef*(y-oldy));
       s:=PicRect.Bottom-PicRect.Top;
       if d>0 then begin
          if PicRect.Top>=d then begin
            PicRect.Top:=PicRect.Top-d;
            PicRect.Bottom:=PicRect.Bottom-d;
          end else begin
            PicRect.Top:=0;
            PicRect.Bottom:=PicRect.Top+s;
          end;
       end;

{There was a bug in the fragment below. Thanks to all, who reported this bug to me}
      if d<0 then begin
          if PicRect.Bottom<FBitmap.Height+d then begin
            PicRect.Top:=PicRect.Top-d;
            PicRect.Bottom:=PicRect.Bottom-d;
          end else begin
            PicRect.Bottom:=FBitmap.Height;
            PicRect.Top:=PicRect.Bottom-s;
          end;
       end;


       oldx:=x; oldy:=y;
       if FForceRepaint then Repaint
                        else Invalidate;
    end;
end;



procedure TZImage.MouseUp(Button: TMouseButton; Shift: TShiftState;
                          X, Y: Integer);
var coef:Double;
    t:integer;
    left,right,top,bottom : integer;
begin

   if FMouse=mNone then Exit;
   if x>ShowRect.Right then x:=ShowRect.Right;
   if y>ShowRect.Bottom then y:=ShowRect.Bottom;
   if FMouse=mZoom then begin  //calculate new PicRect
     t:=startx;
     startx:=Min(startx,x);
     x:=Max(t,x);
     t:=starty;
     starty:=Min(starty,y);
     y:=Max(t,y);
     FMouse:=mNone;
     MouseCapture:=False;
//enable the following if you want to zoom-out by dragging in the opposite direction}
{     if Startx>x then begin
        DblClick;
        Exit;
     end;}
     if Abs(x-startx)<5 then Exit;
     //showmessage('picrect Left='+inttostr(picrect.Left)+' right='+inttostr(picrect.Right)+' top='+inttostr(picrect.Top)+' bottom='+inttostr(picrect.Bottom));
     //startx and start y is teh starting x/y of the selected area
     //x and y is the ending x/y of the selected area
     if (x - startx < y - starty) then
     begin
       while (x - startx < y - starty) do
       begin
          x := x + 100;
          startx := startx - 100;
       end;
     end

     else if (x - startx > y - starty) then
     begin
        while (x - startx > y - starty) do
        begin
            y := y + 100;
            starty := starty - 100;
        end;
     end;

//picrect is the size of whole area
//PicRect.top and left are 0,0
//IFs were added in v.1.2 to avoid zero-divide
     if (PicRect.Right=PicRect.Left)
     then
        coef := 100000
     else
        coef:=ShowRect.Right/(PicRect.Right-PicRect.Left);    //if new screen coef= 1
     left:=Round(PicRect.Left+startx/coef);
     Right:=Left+Round((x-startx)/coef);

     if (PicRect.Bottom=PicRect.Top)
     then
        coef := 100000
     else
        coef:=ShowRect.Bottom/(PicRect.Bottom-PicRect.Top);
     Top:=Round(PicRect.Top+starty/coef);
     Bottom:=Top+Round((y-starty)/coef);
     //showmessage(inttostr(left)+' '+inttostr(Right)+' '+inttostr(top)+' '+inttostr(bottom));

     zoom(left,right,top,bottom);
     ValueLeft := left;
     ValueRight := Right;
     ValueTop := top;
     ValueBottom := bottom;
     end;
   if FMouse=mDrag then begin
     FMouse:=mNone;
     Canvas.Pen.Mode:=pmCopy;
     Screen.Cursor:=crDefault;
   end;

   Invalidate;
end;

procedure TZImage.DblClick;
begin
   zoom(0,FBitMap.Width,0,FBitMap.Height);
   ValueLeft := 0;
   ValueRight := FBitMap.Width;
   ValueTop := 0;
   ValueBottom := FBitMap.Height;
   //PicRect:=Rect(0,0,FBitmap.Width,FBitmap.Height);
   Invalidate;
end;

procedure TZImage.SetBitmap(b:TBitmap);
begin
   FBitmap.Assign(b);
   PicRect:=Rect(0,0,b.Width, b.Height);
   Invalidate;
end;

procedure TZImage.SetBorderWidth(w:integer);
begin
   FBorderWidth:=w;
   Invalidate;
end;

procedure TZImage.SetShowBorder(s:boolean);
begin
   FShowBorder:=s;
   Invalidate;
end;

procedure TZImage.SetProportional(b:boolean);
begin
   FProportional:=b;
   Invalidate;
end;

procedure Register;
begin
  RegisterComponents('Custom', [TZImage]);
end;

end.

With this code you can register the componet ZImage and see how it runs.. if needed

like image 953
Glen Morse Avatar asked Jun 15 '12 22:06

Glen Morse


People also ask

How do you keep aspect ratio when resizing?

Press-and-hold the Shift key, grab a corner point, and drag inward to resize the selection area. Because you're holding the Shift key as you scale, the aspect ratio (the same ratio as your original photo) remains exactly the same.

How do I lock aspect ratio?

So how do you lock the aspect ratio of a photo in PowerPoint? Simply select the picture and right click on it. Then select the “Format Picture” option. On the dialogue box that opens, click on “Size & Properties”, and tick the “Lock Aspect Ratio” option.

Why does zoom change my aspect ratio?

For normal meeting, if you do not check “Enable HD“, the captured video ratio is 4:3. But if bandwidth is good enough, the camera size will be updated to HD mode (16:9) automatically after someone joins the meeting which is HD enabled. This is the current design.

How do I change the aspect ratio on my zoom phone?

View your video feed and change your camera. Camera: Select the camera you want Zoom to use. Camera settings: Select Original Ratio (usually a 4:3 aspect ratio) or HD (usually 16:9 aspect ratio), as well as Mirror my video, which will horizontally flip your video.


1 Answers

The question is clear, but I think the problem answering it is how not to rewrite the complete code to be understandable for you. And since I am better at coding then explaining, I did.

I think you are searching for something like the following:

unit ZImage2;

interface

uses
  Windows, Messages, Classes, Controls, Graphics, StdCtrls, ExtCtrls, Math;

const
  DefAnimDuration = 500;

type
  TZImage = class(TGraphicControl)
  private
    FAlignment: TAlignment;
    FAnimDuration: Cardinal;
    FAnimRect: TRect;
    FAnimStartTick: Cardinal;
    FAnimTimer: TTimer;
    FBuffer: TBitmap;
    FCropRect: TRect;
    FImgRect: TRect;
    FLayout: TTextLayout;
    FPicture: TPicture;
    FPrevCropRect: TRect;
    FProportional: Boolean;
    FProportionalCrop: Boolean;
    FScale: Single;
    FSelColor: TColor;
    FSelecting: Boolean;
    FSelPoint: TPoint;
    FSelRect: TRect;
    procedure Animate(Sender: TObject);
    function HasGraphic: Boolean;
    procedure PictureChanged(Sender: TObject);
    procedure RealignImage;
    procedure SetAlignment(Value: TAlignment);
    procedure SetLayout(Value: TTextLayout);
    procedure SetPicture(Value: TPicture);
    procedure SetProportional(Value: Boolean);
    procedure UpdateBuffer;
  protected
    function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; override;
    procedure ChangeScale(M: Integer; D: Integer); override;
    procedure DblClick; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X,
      Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X,
      Y: Integer); override;
    procedure Paint; override;
    procedure Resize; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Reset;
    function ScreenToGraphic(R: TRect): TRect;
    procedure Zoom(const ACropRect: TRect);
    procedure ZoomSelection(const ASelRect: TRect);
  published
    property Alignment: TAlignment read FAlignment write SetAlignment
      default taLeftJustify;
    property AnimDuration: Cardinal read FAnimDuration write FAnimDuration
      default DefAnimDuration;
    property Layout: TTextLayout read FLayout write SetLayout default tlTop;
    property Picture: TPicture read FPicture write SetPicture;
    property Proportional: Boolean read FProportional write SetProportional
      default False;
    property ProportionalCrop: Boolean read FProportionalCrop
      write FProportionalCrop default True;
    property SelColor: TColor read FSelColor write FSelColor default clWhite;
  published
    property Align;
    property Anchors;
    property AutoSize;
    property Color;
  end;

implementation

function FitRect(const Boundary: TRect; Width, Height: Integer;
  CanGrow: Boolean; HorzAlign: TAlignment; VertAlign: TTextLayout): TRect;
var
  W: Integer;
  H: Integer;
  Scale: Single;
  Offset: TPoint;
begin
  Width := Max(1, Width);
  Height := Max(1, Height);
  W := Boundary.Right - Boundary.Left;
  H := Boundary.Bottom - Boundary.Top;
  if CanGrow then
    Scale := Min(W / Width, H / Height)
  else
    Scale := Min(1, Min(W / Width, H / Height));
  Result := Rect(0, 0, Round(Width * Scale), Round(Height * Scale));
  case HorzAlign of
    taLeftJustify:
      Offset.X := 0;
    taCenter:
      Offset.X := (W - Result.Right) div 2;
    taRightJustify:
      Offset.X := W - Result.Right;
  end;
  case VertAlign of
    tlTop:
      Offset.Y := 0;
    tlCenter:
      Offset.Y := (H - Result.Bottom) div 2;
    tlBottom:
      Offset.Y := H - Result.Bottom;
  end;
  OffsetRect(Result, Boundary.Left + Offset.X, Boundary.Top + Offset.Y);
end;

function NormalizeRect(const Point1, Point2: TPoint): TRect;
begin
  Result.Left := Min(Point1.X, Point2.X);
  Result.Top := Min(Point1.Y, Point2.Y);
  Result.Right := Max(Point1.X, Point2.X);
  Result.Bottom := Max(Point1.Y, Point2.Y);
end;

{ TZImage }

procedure TZImage.Animate(Sender: TObject);
var
  Done: Single;
begin
  Done := (GetTickCount - FAnimStartTick) / FAnimDuration;
  if Done >= 1.0 then
  begin
    FAnimTimer.Enabled := False;
    FAnimRect := FCropRect;
  end
  else
    with FPrevCropRect do
      FAnimRect := Rect(
        Left + Round(Done * (FCropRect.Left - Left)),
        Top + Round(Done * (FCropRect.Top - Top)),
        Right + Round(Done * (FCropRect.Right - Right)),
        Bottom + Round(Done * (FCropRect.Bottom - Bottom)));
  UpdateBuffer;
  RealignImage;
  Invalidate;
end;

function TZImage.CanAutoSize(var NewWidth, NewHeight: Integer): Boolean;
begin
  Result := True;
  if not (csDesigning in ComponentState) or HasGraphic then
  begin
    if Align in [alNone, alLeft, alRight] then
      NewWidth := Round(FScale * FPicture.Width);
    if Align in [alNone, alTop, alBottom] then
      NewHeight := Round(FScale * FPicture.Height);
  end;
end;

procedure TZImage.ChangeScale(M, D: Integer);
var
  SaveAnchors: TAnchors;
begin
  SaveAnchors := Anchors;
  Anchors := [akLeft, akTop];
  FScale := FScale * M / D;
  inherited ChangeScale(M, D);
  Anchors := SaveAnchors;
end;

constructor TZImage.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := [csCaptureMouse, csClickEvents, csOpaque, csDoubleClicks];
  FAnimTimer := TTimer.Create(Self);
  FAnimTimer.Interval := 15;
  FAnimTimer.OnTimer := Animate;
  FAnimDuration := DefAnimDuration;
  FBuffer := TBitmap.Create;
  FPicture := TPicture.Create;
  FPicture.OnChange := PictureChanged;
  FProportionalCrop := True;
  FScale := 1.0;
  FSelColor := clWhite;
end;

procedure TZImage.DblClick;
begin
  if not HasGraphic then
    Reset
  else
    Zoom(Rect(0, 0, FPicture.Width, FPicture.Height));
  inherited DblClick;
end;

destructor TZImage.Destroy;
begin
  FPicture.Free;
  FBuffer.Free;
  inherited Destroy;
end;

function TZImage.HasGraphic: Boolean;
begin
  Result := (Picture.Width > 0) and (Picture.Height > 0);
end;

procedure TZImage.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  if (Button = mbRight) and HasGraphic and PtInRect(FImgRect, Point(X, Y)) then
  begin
    FSelPoint.X := X;
    FSelPoint.Y := Y;
    FSelRect := Rect(X, Y, X, Y);
    FSelecting := True;
    Canvas.Brush.Color := FSelColor;
    Canvas.DrawFocusRect(FSelRect);
  end;
  inherited MouseDown(Button, Shift, X, Y);
end;

procedure TZImage.MouseMove(Shift: TShiftState; X, Y: Integer);
const
  HorzAlign: array[Boolean] of TAlignment = (taLeftJustify, taRightJustify);
  VertAlign: array[Boolean] of TTextLayout = (tlTop, tlBottom);
begin
  if FSelecting and PtInRect(FImgRect, Point(X, Y)) then
  begin
    Canvas.DrawFocusRect(FSelRect);
    FSelRect := NormalizeRect(FSelPoint, Point(X, Y));
    if (not FProportionalCrop) then
      FSelRect := FitRect(FSelRect, FPicture.Graphic.Width,
        FPicture.Graphic.Height, True, HorzAlign[X < FSelPoint.X],
        VertAlign[Y < FSelPoint.Y]);
    Canvas.DrawFocusRect(FSelRect);
  end;
  inherited MouseMove(Shift, X, Y);
end;

procedure TZImage.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  if FSelecting then
  begin
    FSelecting := False;
    Canvas.DrawFocusRect(FSelRect);
    if (Abs(X - FSelPoint.X) > Mouse.DragThreshold) or
        (Abs(Y - FSelPoint.Y) > Mouse.DragThreshold) then
      ZoomSelection(FSelRect);
  end;
  inherited MouseUp(Button, Shift, X, Y);
end;

procedure TZImage.Paint;
begin
  Canvas.Brush.Color := Color;
  if HasGraphic then
  begin
    Canvas.StretchDraw(FImgRect, FBuffer);
    if FSelecting then
      Canvas.DrawFocusRect(FSelRect);
    with FImgRect do
      ExcludeClipRect(Canvas.Handle, Left, Top, Right, Bottom);
  end;
  Canvas.FillRect(Canvas.ClipRect);
end;

procedure TZImage.PictureChanged(Sender: TObject);
begin
  Reset;
end;

procedure TZImage.RealignImage;
begin
  if not HasGraphic then
    FImgRect := Rect(0, 0, 0, 0)
  else if FProportional then
    FImgRect := ClientRect
  else
    FImgRect := FitRect(ClientRect, FBuffer.Width, FBuffer.Height, True,
      FAlignment, FLayout);
end;

procedure TZImage.Reset;
begin
  FCropRect := Rect(0, 0, FPicture.Width, FPicture.Height);
  FAnimRect := FCropRect;
  UpdateBuffer;
  RealignImage;
  Invalidate;
end;

procedure TZImage.Resize;
begin
  RealignImage;
  inherited Resize;
end;

function TZImage.ScreenToGraphic(R: TRect): TRect;
var
  CropWidth: Integer;
  CropHeight: Integer;
  ImgWidth: Integer;
  ImgHeight: Integer;
begin
  CropWidth := FCropRect.Right - FCropRect.Left;
  CropHeight := FCropRect.Bottom - FCropRect.Top;
  ImgWidth := FImgRect.Right - FImgRect.Left;
  ImgHeight := FImgRect.Bottom - FImgRect.Top;
  IntersectRect(R, R, FImgRect);
  OffsetRect(R, -FImgRect.Left, -FImgRect.Top);
  Result := Rect(
    FCropRect.Left + Round(CropWidth * (R.Left / ImgWidth)),
    FCropRect.Top + Round(CropHeight * (R.Top / ImgHeight)),
    FCropRect.Left + Round(CropWidth * (R.Right / ImgWidth)),
    FCropRect.Top + Round(CropHeight * (R.Bottom / ImgHeight)));
end;

procedure TZImage.SetAlignment(Value: TAlignment);
begin
  if FAlignment <> Value then
  begin
    FAlignment := Value;
    RealignImage;
    Invalidate;
  end;
end;

procedure TZImage.SetLayout(Value: TTextLayout);
begin
  if FLayout <> Value then
  begin
    FLayout := Value;
    RealignImage;
    Invalidate;
  end;
end;

procedure TZImage.SetPicture(Value: TPicture);
begin
  FPicture.Assign(Value);
end;

procedure TZImage.SetProportional(Value: Boolean);
begin
  if FProportional <> Value then
  begin
    FProportional := Value;
    RealignImage;
    Invalidate;
  end;
end;

procedure TZImage.UpdateBuffer;
begin
  if HasGraphic then
  begin
    FBuffer.Width := FAnimRect.Right - FAnimRect.Left;
    FBuffer.Height := FAnimRect.Bottom - FAnimRect.Top;
    FBuffer.Canvas.Draw(-FAnimRect.Left, -FAnimRect.Top, FPicture.Graphic);
  end;
end;

procedure TZImage.Zoom(const ACropRect: TRect);
begin
  if HasGraphic then
  begin
    FPrevCropRect := FAnimRect;
    FCropRect := ACropRect;
    if FAnimDuration = 0 then
    begin
      FAnimRect := FCropRect;
      UpdateBuffer;
      RealignImage;
      Invalidate;
    end
    else
    begin
      FAnimStartTick := GetTickCount;
      FAnimTimer.Enabled := True;
    end;
  end;
end;

procedure TZImage.ZoomSelection(const ASelRect: TRect);
begin
  Zoom(ScreenToGraphic(ASelRect));
end;

end.

Sample code:

procedure TForm1.FormCreate(Sender: TObject);
begin
  FImage := TZImage.Create(Self);
  FImage.SetBounds(10, 10, 200, 300);
  FImage.Picture.LoadFromFile('D:\Pictures\Mona_Lisa.jpg');
  FImage.Alignment := taCenter;
  FImage.Layout := tlCenter;
  FImage.AutoSize := True;
  FImage.Parent := Self;
end;

Sample image

like image 69
NGLN Avatar answered Oct 20 '22 17:10

NGLN