How to Crop an Image and Save to file

Not every pixel of a photo is important. Sometimes we need to just crop out some of the area of a photo. We learn how to crop an image and save the cropped version in a file.

We all take photos. We take photos of people, trees, sky, objects and many unimaginable things. Among these photos there are some photos which are just not right. They have unnecessary portions that if got rid of, can make the photo more focused and a perfect one. So today we see how to crop an image.

Concept

Cropping an image means basically to eliminate some pixels and draw the rest of the picture. The user opens a photo, then selects a rectangular area to be cropped. We, the programers, then take only the part of the image that is inside the rectangular area and draw it somewhere. The image that we draw is the cropped image. We actually copy certain part of the image.

the procedure by which an image is cropped- opening, selection, drawing

It’s very easy if you know how to use TCanvas.CopyRect procedure. It has the following syntax:

1
2
3
4
5
public procedure TCanvas.CopyRect(
  const Dest: TRect;
  SrcCanvas: TCanvas;
  const Source: TRect
); virtual;

The LCL Manual explains CopyRect by saying:

Copies the rectangle found at Source in SrcCanvas to the destination position Dest

  • Dest is the rectangular area where the cropped image will be shown.
  • SrcCanvas is the canvas from which we will get our original image.
  • Source is the cropped rectangular area. The part which we will copy.

As you can see, we are actually drawing a part of a TCanvas to somewhere else. We are not actually cropping the image.

Tutorial

Start Lazarus IDE.

Create a new Application Project (Project -> New Project -> Application -> OK). Now drop a TFileNameEdit [from Misc tab] and a TButton on the form (or TBitBtn [Additional tab] if you are interested in using an icon for the button). Name the TButton as btnSave. These 2 components are for opening an image and then saving the cropped image.

Image crop project form layout, pic 1.

You can set the Filter property of FileNameEdit1 as:

1
*.bmp;*.xpm;*.png;*.pbm;*.ppm;*.ico;*.icns;*.cur;*.jpg;*.jpeg;*.jpe;*.jfif;*.tif;*.tiff;*.gif

For saving the cropped file we would also need a TSaveDialog. Drop one TSaveDialog (from the Dialogs tab) and set its Filter as:

1
Bitmap File (*.bmp)|*.bmp

We will have 2 TImages. One will have the original image and another one will have the cropped image. The image will be cropped when the user drags a rectangle over the first TImage. But if the user opens a large image, then the TImage will have to have a scrolling function. So we will have to create a TScrollbox and put our TImage in it. We know that everything we put inside a TScrollbox automatically has scrollbars if its dimensions are outside its area.

So, we will create 2 TScrollbox components on the form. TScrollbox component can be found on Additional tab of the toolbar.

Image crop project form layout, pic 2.

Now, put 2 Timages inside those. If you are not sure how to put them inside the TScrollbox then I’d suggest you select the Timage tool from the toolbar then start dragging inside the area of a TScrollbox. Then the TImage will be created inside the TScrollbox. Even the Object Inspector will show the hierarchy you achieved.

Creating Timage inside a container, view on Object Inspector.

Create another TImage inside the other TScrollBox. Image1 on the left will be our original image and Image2 at the right will be our cropped image. Set Image1‘s AutoSize property to True, so that it sizes automatically according to image size. Also, set the Left and Top property of both the images to 0 (zero).

Now, to have a smoother scrolling behavior, we need to set the HorzScrollBar->Tracking and VertScrollBar->Tracking property to True.

I’m sure you have done all the things I have said. Another little thing is the selection rectangle. Create a TShape [form Additional tab] inside the ScrollBox1 in the left. Set its Name property to Sel. You can customize it the way you like. I have set its Brush->Style property to bsClear; Pen->Color to clGreen and Pen->Style to psDot. Set its Visible property to False because we only want to show it when the user selects an area of the image, but not always.

My form design is like below. I have also opened a default image for testing in Image1.

Now to coding…

First, add the following variables under the first var clause (usually under the Form1: TForm1; line). If you need to switch to code view, then use F12.

1
2
3
4
5
6
7
var
  ...
  ...
  PrevX, PrevY: Integer;
  MouseIsDown: Boolean;

  Bmp2: TBitmap;

Switch to Form view (F12). Double click the Form, then enter:

1
2
3
4
5
6
7
8
9
10
11
12
procedure TForm1.FormCreate(Sender: TObject);
begin
  Bmp2:=TBitmap.Create;

  Bmp2.Width:=Screen.Width;
  Bmp2.Height:=Screen.Height;

  Bmp2.Canvas.Brush.Color:=clWhite;
  Bmp2.Canvas.FillRect(0,0, Bmp2.Canvas.Width, Bmp2.Canvas.Height);
  // we trigger the OnPaint event to draw Bmp2
  Image2Paint(Sender);
end;

Now let’s let the user open images. Double click the FileNameEdit1 and enter:

1
2
3
4
5
procedure TForm1.FileNameEdit1Change(Sender: TObject);
begin
  if FileExistsUTF8(FileNameEdit1.FileName) then
    Image1.Picture.LoadFromFile(FileNameEdit1.FileName);
end;

Now select Image1 and add the following code on its OnMouseDown event (Object Inspector -> Events -> OnMouseDown -> […]):

1
2
3
4
5
6
7
8
9
10
11
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then begin
    MouseIsDown:=True;
    PrevX:=X;
    PrevY:=Y;
    Sel.Visible:=True;
    Image1MouseMove(Sender,Shift,X,Y);
  end;
end;

On Image1‘s OnMouseMove event, add:

1
2
3
4
5
6
7
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if MouseIsDown = true then begin
    Sel.SetBounds(prevx,prevy,X-prevx,y-prevy);
  end;
end;

On Image1‘s OnMouseUp event, add:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  rect1, rect2: TRect;
  destwidth, destheight: Integer;
begin
  MouseIsDown:=False;
  Sel.Visible:=False;
  // if we do not refresh, then the Sel will
  // be also drawn !
  Image1.Refresh;

  // we keep width and height in variables
  // because we will need it many times
  destwidth:=X-PrevX;
  destheight:=Y-PrevY;

  //// We prepare 2 rects for cropping ////
  // Destination rectangle
  // ...where the cropped image would be drawn
  with rect1 do begin
    Left:=0;
    Top:=0;
    Right:=Left+destwidth;
    Bottom:=Top+destheight;
  end;

  // Source rectangle
  // ...where we crop from
with rect2 do begin
Left:=PrevX-abs(ScrollBox1.HorzScrollBar.Position);
Top:=PrevY-abs(ScrollBox1.VertScrollBar.Position);
Right:=Left+destwidth;
Bottom:=Top+destheight;
end;

// we do the actual drawing
Bmp2.SetSize(destwidth, destheight);
Image2.SetBounds(0,0,destwidth,destheight);
Bmp2.Canvas.CopyRect(rect1, Image1.Canvas, rect2);

Image2Paint(Sender);
end;

(UPDATE: The above code has been updated to fix a drawing misbehavior when scrolled before cropping.)

On Image2‘s OnPaint event, enter:

1
2
3
4
procedure TForm1.Image2Paint(Sender: TObject);
begin
  Image2.Canvas.Draw(0,0,Bmp2);
end;

Double click on btnSave and enter:

1
2
3
4
5
6
procedure TForm1.btnSaveClick(Sender: TObject);
begin
  SaveDialog1.Execute;
  if (SaveDialog1.FileName <> '') then
    bmp2.SaveToFile(SaveDialog1.FileName);
end;

Run It

Now Run the project (F9 or Run -> Run).

Lazarus Image crop example with open and save options (runtime)

Now open an image using the FileNameEdit. The image will show in the left TImage. Now drag to select a rectangular area over the image. It will produce a cropped image on the right. Click the button to save the cropped image to a file of your choice.

Image crop example lazarus ide

Let me know if you need explanations of these codes. I’d be happy to explain it for you. Just post a comment and ask.

You can also make it do the following. Extending is a great practice for improving your programing skills.

  • Paste image from clipboard to let it resize. We often need to take a screenshot and crop it to share it over the internet.
  • Take a snapshot of the screen and offer to crop it (without need to press Print Screen button).
  • Save as many formats, such as compressed JPEGs or GIFs.
  • Use a single TImage to show both original and cropped image (Just like Gimp or Photoshop has a single canvas for showing both, not two canvases).

Downloads

You can download the source code for the tutorial project and executable/EXE files from the links below: