4

I am working with delphi. I have TImage, to which I assign a bitmap.

imgmain.Picture.Bitmap := bmpMain;
imgmain.Picture.Bitmap.PixelFormat := pf24bit;

imgmain is object of TImage and bmpMain is object of TBitmap

I want to zoom my image. I have one trackbar on my form and as I click on trackbar the image should get zoom. What should I do?
Thank You.

Edit :
I found some solution at here It works but it cut my image.

Himadri
  • 2,922
  • 5
  • 32
  • 56

1 Answers1

11

The code you refer to sets up a transformation from one coordinate space to another, I didn't notice anything that would cut/crop your image there. However, instead of having an inversely proportional zoom factor I'd rather have, easy to understand, linear scaling. Also, I see no reason switching map modes depending on the scaling factor, I would modify the SetCanvasZoomFactor like this;

procedure SetCanvasZoomPercent(Canvas: TCanvas; AZoomPercent: Integer);
begin
  SetMapMode(Canvas.Handle, MM_ISOTROPIC);
  SetWindowExtEx(Canvas.Handle, 100, 100, nil);
  SetViewportExtEx(Canvas.Handle, AZoomPercent, AZoomPercent, nil);
end;

A simplified (no error checking) working example with a bitmap loaded to a TImage, scaled via a TrackBar could be like the below. Note that the above function is inlined in the TrackBar's OnChange event.

type
  TForm1 = class(TForm)
    imgmain: TImage;
    TrackBar1: TTrackBar;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure TrackBar1Change(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    bmpmain: TBitmap;
  [..]

[...]
procedure TForm1.FormCreate(Sender: TObject);
begin
  bmpmain := TBitmap.Create;
  bmpmain.LoadFromFile(ExtractFilePath('samplebitmap.bmp');
  bmpmain.PixelFormat := pf32bit; // No significance, just seems faster here than pf24bit

  TrackBar1.Min := 10;
  TrackBar1.Max := 200;
  TrackBar1.Frequency := 10;
  TrackBar1.PageSize := 10;
  TrackBar1.Position := 100; // Fires OnChange
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 bmpmain.Free;
end;

procedure TForm1.TrackBar1Change(Sender: TObject);
var
  Zoom, x, y: Integer;
begin
  Zoom := TrackBar1.Position;
  if not (Visible or (Zoom = 100)) or (Zoom = 0) then
    Exit;

  SetMapMode(imgmain.Canvas.Handle, MM_ISOTROPIC);
  SetWindowExtEx(imgmain.Canvas.Handle, 100, 100, nil);
  SetViewportExtEx(imgmain.Canvas.Handle, Zoom, Zoom, nil);
  x := imgmain.Width * 50 div Zoom - bmpmain.Width div 2;
  y := imgmain.Height * 50 div Zoom - bmpmain.Height div 2;
  imgmain.Canvas.Draw(x, y, bmpmain);
  if (x > 0) or (y > 0) then begin
    imgmain.Canvas.Brush.Color := clWhite;
    ExcludeClipRect(imgmain.Canvas.Handle, x, y, x + bmpmain.Width, y + bmpmain.Height);
    imgmain.Canvas.FillRect(imgmain.Canvas.ClipRect);
  end;

  Label1.Caption := 'Zoom: ' + IntToStr(TrackBar1.Position) + '%';
end;


edit: same code with a TImage in a ScrollBox;

type
  TForm1 = class(TForm)
    TrackBar1: TTrackBar;
    Label1: TLabel;
    ScrollBox1: TScrollBox;
    imgmain: TImage;
    procedure FormCreate(Sender: TObject);
    procedure TrackBar1Change(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    bmpmain: TBitmap;
  [...]
[...]

const
  FULLSCALE = 100;

procedure TForm1.FormCreate(Sender: TObject);
begin
  imgmain.Left := 0;
  imgmain.Top := 0;

  bmpmain := TBitmap.Create;
  bmpmain.LoadFromFile(ExtractFilePath(Application.ExeName) + '610x.bmp');
  bmpmain.PixelFormat := pf32bit;

  TrackBar1.Min := FULLSCALE div 10;   // %10
  TrackBar1.Max := FULLSCALE * 2;      // %200
  TrackBar1.PageSize := (TrackBar1.Max - TrackBar1.Min) div 19;
  TrackBar1.Frequency := TrackBar1.PageSize;
  TrackBar1.Position := FULLSCALE;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  bmpmain.Free;
end;

procedure TForm1.TrackBar1Change(Sender: TObject);
var
  Zoom: Integer;
begin
  Zoom := TrackBar1.Position;
  if not (Visible or (Zoom = FULLSCALE)) or (Zoom = 0) then
    Exit;

  SetMapMode(imgmain.Canvas.Handle, MM_ISOTROPIC);
  SetWindowExtEx(imgmain.Canvas.Handle, FULLSCALE, FULLSCALE, nil);
  SetViewportExtEx(imgmain.Canvas.Handle, Zoom, Zoom, nil);

  imgmain.Width := Round(bmpmain.Width * Zoom / FULLSCALE);
  imgmain.Height := Round(bmpmain.Height * Zoom / FULLSCALE);
  if Assigned(imgmain.Picture.Graphic) then begin
    imgmain.Picture.Graphic.Width := imgmain.Width;
    imgmain.Picture.Graphic.Height := imgmain.Height;
  end;
  imgmain.Canvas.Draw(0, 0, bmpmain);

  Label1.Caption := 'Zoom: ' +
      IntToStr(Round(TrackBar1.Position / FULLSCALE * 100)) + '%';
end;
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • @Sertac Thanx, It is better than the code I was using. But can you tell me what is significance of line : imgmain.Canvas.Draw(x,y,bmpmain); because, before this line we are not changing bmpmain then why we are drawing it to imgmain? And by words cutting the image, I mean that after zoom It didn't increase the actual length of image, But I want the full image which I didn't get from this code too. One more thing, I have put the image into TScrollBar, Is this creating the problem? – Himadri Jun 14 '10 at 05:31
  • 1
    @Himadri - we are never changing bmpmain, we are only changing the relation betwen logical units and device units on the TImage canvas. Let me try with an example; Suppose you have a bitmap of width 96px, if your Screen.PixelsPerInch is also 96px `imgmain.Canvas.Draw(x,y,bmpmain)` would draw a 1" width bitmap on the TImage. In isotropic map mode, if you set the horizontal window extent to 100 and horizontal viewport extent to 200, you're saying that 100 logical units on the x axis would be represented with 200px. So the same call would draw the bitmap 192px or 2" or twice the width. – Sertac Akyuz Jun 14 '10 at 09:34
  • @Himadri- You can put the TImage in a scroll box of course. Whenever you change the scaling, before drawing on the image, you should calculate and set the new width/height of the image. For the example above it would be f.i. `imgmain.Width := bmpmain.Width * Zoom div 100;` – Sertac Akyuz Jun 14 '10 at 09:59
  • @Sertac I wrote this line but it is not changing width of imgmain. Am I missing setting some property? My problem of cut image is yet not solved. – Himadri Jun 15 '10 at 10:32
  • @Himadri - I think I see what you mean. It seems that if there is already a graphic assigned to the picture of an image, setting the image's size does not have an effect on the graphic's size. I've updated the answer, please try with the new code. – Sertac Akyuz Jun 15 '10 at 13:26