Search code examples
delphi

FMX TImageviewer : get coordinate in used Bitmap


while moving my mouse over a bitmap inside a TImageviewer component in FMX framework, I need to get the position of this pixel inside the original bitmap.
here come my not working code, while zooming and moving to a selected position inside the bitmap, the x/y coordinate change, they should stay independent from the used zoomlevel.

procedure TmainForm.imgviewer_layoutMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Single);
var
  ImageViewer: TImageViewer;
  Image: TBitmap;
  ImageX, ImageY: Single;
  ScaleX, ScaleY, BitmapScale: Single;
begin
  ImageViewer := Sender as TImageViewer;
  Image := ImageViewer.Bitmap;

  // Ensure we have an image loaded in the ImageViewer
  if Assigned(Image) and not Image.IsEmpty then
  begin
    BitmapScale := Image.BitmapScale;

    // Calculate the scale factors of the image within the ImageViewer
    ScaleX := ImageViewer.Width / (Image.Width * BitmapScale);
    ScaleY := ImageViewer.Height / (Image.Height * BitmapScale);

    // Adjust the X, Y to the image coordinates
    ImageX := X / ScaleX;
    ImageY := Y / ScaleY;

    // Ensure coordinates are within the bounds of the image
    if (ImageX >= 0) and (ImageX <= Image.Width) and
       (ImageY >= 0) and (ImageY <= Image.Height) then
    begin
      UpdateStatus('INFO LAYOUT DOWN ' + Point2Str(ImageX, ImageY));
    end
    else
    begin
      UpdateStatus('INFO LAYOUT DOWN: Outside Image');
    end;
  end
  else
  begin
    UpdateStatus('INFO LAYOUT DOWN: No Image Loaded');
  end;
end;

Solution

  • This should give you what you're after:

    procedure TmainForm.imgviewer_layoutMouseDown(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    var ImageViewer:       TImageViewer;
        Image:             TBitmap;
        ImageLeft,
        ImageTop:          Single;
        ImageX,
        ImageY:            Single;
        ScaledImageWidth,
        ScaledImageHeight: Single;
        Scale:             Single;
    begin
        //Get controls
      ImageViewer:=Sender as TImageViewer;
      Image:=ImageViewer.Bitmap;
    
      if Assigned(Image) and not Image.IsEmpty then begin
    
        //Get scaled image size
        Scale:=Viewer.BitmapScale;
        ScaledImageWidth:=Image.Width*Scale;
        ScaledImageHeight:=Image.Height*Scale;
    
        //Get bitmap's top and left positions.
        ImageLeft:=(ImageViewer.Width-ScaledImageWidth)/2;
        if ImageLeft<0 then ImageLeft:=0;
        ImageTop:=(ImageViewer.Height-ScaledImageHeight)/2;
        if ImageTop<0 then ImageTop:=0;
    
        //Get bitmap's mouse coordinates
        ImageX:=(X+ImageViewer.ViewportPosition.X-ImageLeft)/Scale;
        ImageY:=(Y+ImageViewer.ViewportPosition.Y-ImageTop)/Scale;
    
        //Report results
        if (X>=ImageLeft) and (X<=ImageLeft+ScaledImageWidth)
           and (Y>=ImageTop) and (Y<=ImageTop+ScaledImageHeight)
        then UpdateStatus('INFO LAYOUT DOWN '+Point2Str(ImageX,ImageY))
        else UpdateStatus('INFO LAYOUT DOWN: OutsideImage');
      end
      else UpdateStatus('INFO LAYOUT DOWN: No Image Loaded');
    end;