2

I need create a crop effect to my app. I have a TRectangle over a TImage, and I need when the user press the save button, copy just the area that the TRectangle uses. There is some way that I can cut just a specific area from the Image1.Bitmap? I printed a image to better ilustrate what I need:

enter image description here

Diego Bittencourt
  • 595
  • 10
  • 28
  • You better use a canvas which you can control the scale. Don't just use any random image control. If it were me, I'd write a custom control for this. But it wouldn't be a very trivial one. – Jerry Dodge Oct 23 '17 at 01:25
  • What is the `WrapMode` that you use? What if it's `Tile` and your selector covers more than one tile of the displayed image? – Victoria Oct 23 '17 at 02:04
  • 1
    The crop procedure would be like this: 1) calculate the scaling of your image and convert the rectangles bounds to the image scale. 2) create a TBitmap and use CopyFromBitmap with the calculated rectangle. This copies a section from your TImage bitmap to the new bitmap. 3) assign the bitmap to your TImage bitmap (if that's what you want). – Hans Oct 23 '17 at 06:34
  • Can you please give me a code example on how to do the step number 2? – Diego Bittencourt Oct 23 '17 at 10:32
  • @Victoria I'm using Fit at the moment, and I don't think I'll need change this. Maybe to stretch... Have you any idea on how I can fix this task? I'm just lost and need some direction. – Diego Bittencourt Oct 23 '17 at 19:10
  • @Jerry Dodge Can you be more specific please, I really need fix this. Thanks man! – Diego Bittencourt Oct 23 '17 at 19:11
  • [This question](https://stackoverflow.com/questions/31159795/how-to-crop-an-fmx-tbitmap) might be useful. – asd-tm Oct 23 '17 at 19:20
  • 1
    The concept is very trivial: Draw your image on a controlled canvas (one which you have 100% control over), and do simple math to determine scale. Surely there are plenty of resources how to extract a portion of an image in Firemonkey. I used them to write my own vector signature control. Only much simpler for you. But please don't expect us to write it for you. – Jerry Dodge Oct 28 '17 at 01:44

2 Answers2

5

Here is a sample that works for me:

procedure TForm1.Button1Click(Sender: TObject);
var
  Bmp: TBitmap;
  xScale, yScale: extended;
  iRect: TRect;
begin

  Bmp := TBitmap.Create;
  xScale := Image1.Bitmap.Width / Image1.Width;
  yScale := Image1.Bitmap.Height / Image1.Height;
  try
    Bmp.Width := round(Rectangle1.Width * xScale);
    Bmp.Height := round(Rectangle1.Height * yScale);
    iRect.Left := round(Rectangle1.Position.X * xScale);
    iRect.Top := round(Rectangle1.Position.Y * yScale);
    iRect.Width := round(Rectangle1.Width * xScale);
    iRect.Height := round(Rectangle1.Height * yScale);
    Bmp.CopyFromBitmap(Image1.Bitmap, iRect, 0, 0);
    Image2.Bitmap := Bmp
  finally
    Bmp.Free;
  end;
end;

I assume here that Rectangle1 has Image1 as its Parent:

enter image description here

Otherwise you will need to consider the offset of Position.X and Position.Y properties.

Here is a result of procedure functioning: enter image description here

asd-tm
  • 3,381
  • 2
  • 24
  • 41
  • 2
    Thank you so much, exactly what I needed!! – Diego Bittencourt Nov 01 '17 at 16:11
  • I tried your solution on the mobile, but in some smartphones with different resolutions and scales ... the image copied from the selection is not correct. why? – acarlomagno Jun 28 '21 at 07:28
  • This method has a poor accurracy, the scale is a Single, the X, Y, Heigh and Width of the rect is a Single, but TRect ask for a Integer, so many "rounds" to convert on code change de dimension of the area cropped. I´m trying to use TCanvas methods to draw the canvas of the TImage to TCanvas of the retangle and then use makesnapshot to get TBitmap from rectangle. but still trying. – Joao Ishiwatari Dec 30 '21 at 14:56
  • @Joao xScale and yScale are extended, not single. Frankly speaking I doubt the mashine epsilon 5.96e-08 - 1.19e-07 of a single really matters in the current case. The 1 px mistake might occur when having resulutions about 10000000 - 100000000 pixels. Otherwise I wonder if you could specify the exact practical task for the higher precision processing. – asd-tm Dec 30 '21 at 17:38
  • @asd-tm is not about type precision, is about convertion. A extended rounded to integer causes significant changes on result. I'm using your code to grab a rect from a timage and the result cames different of the cropped area, the rect area changes more than scale. – Joao Ishiwatari Jan 01 '22 at 12:33
0

Another way to do:

var
  Tmp: TBitmap;
  Bmp: TBitmap;
  iRect: TRect;
begin
  Tmp := TBitmap.Create;
  Tmp := Image1.MakeScreenshot; //ignore the scale, so will F*ck the resolution, but resolve the scale issues
  Bmp := TBitmap.Create;
  try
    Bmp.Width := round(Rectangle1.Width);
    Bmp.Height := round(Rectangle1.Height);
    iRect.Left := round(Rectangle1.Position.X);
    iRect.Top := round(Rectangle1.Position.Y);
    iRect.Width := round(Rectangle1.Width);
    iRect.Height := round(Rectangle1.Height);
    Bmp.CopyFromBitmap(tmp, iRect, 0, 0);
    Image2.Bitmap := Bmp
  finally
    Tmp.Free;
    Bmp.Free;
  end;
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 30 '21 at 18:22