-3

Please, somebody help me !!! I need to draw something and save it as a bmp file. I do it like this:

    procedure TForm1.PaintBox1Paint(Sender: TObject);

begin
   with PaintBox1, canvas do
    begin
    Pen.Style := psDash;
    pen.Width:=4;
    pen.Color:=clBlack;
    moveto(2,2);
    lineto(100, 2);
    end;
end;

procedure TForm1.BtnSaveClick(Sender: TObject);
var bmp : TBitmap;
begin
   bmp := TBitmap.Create;
   try
     bmp.width := paintbox1.Width;
     bmp.height:= paintbox1.Height;
     bmp.Canvas.CopyRect(Rect(0, 0, -bmp.Width,  bmp.Height),PaintBox1.Canvas, PaintBox1.Canvas.ClipRect);//Here creates a black rectangle 
    bmp.savetofile('/Users/stad/Desktop/bit4.bmp');

   finally
   end;
end;

And Finally, create a bitmap with black background. Please may be someday knows?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
user2032083
  • 313
  • 2
  • 4
  • 14
  • `CopyRect` works correctly. Your code does not. Please provide [mcve]. – David Heffernan Mar 20 '17 at 16:23
  • Why my code doesn't work correctly? – user2032083 Mar 20 '17 at 16:28
  • Do you realize you have a minus sign before bmp.Width? – Sertac Akyuz Mar 20 '17 at 16:32
  • I forgot to delete it before post. i try many approaches – user2032083 Mar 20 '17 at 16:35
  • The real problem is probably that the paint box has a canvas that is transient. It is valid during the `OnPaint` event and not valid at other times. Paint to an off screen bitmap. Display that in your `OnPaint`. Use the off screen bitmap to save. May be. We could check that stuff out if we had code that we could run. You could readily produce such code. A [mcve]. Why didn't you do that? Was it too much effort for you? Easier for you if we make that effort? Even if we end up with different code from you? Please don't do this again. – David Heffernan Mar 20 '17 at 16:35
  • Thank you ! But I don't understand clearly what does it mean : "Paint to an off screen bitmap. Display that in your OnPaint. Use the off screen bitmap to save." – user2032083 Mar 20 '17 at 16:38
  • Yes, if i load my source it will more better. But I don't know how to do it – user2032083 Mar 20 '17 at 16:45
  • We don't want your entire source code. Just a [mcve]. Presumably you followed that link and read it in detail? – David Heffernan Mar 20 '17 at 17:00
  • I got it. Ok, but if you can to look my code please [link](http://dropmefiles.com/Ew2Zv) – user2032083 Mar 20 '17 at 17:56
  • 1
    Nope. MCVE in the question. – David Heffernan Mar 20 '17 at 18:43

1 Answers1

0

The problem is with the third argument to CopyRect; the source rectangle. It's not what you expect and is too large. In fact, if you magnify the output bitmap, you'll find a squeezed version of the source image in the top left.

A canvas' clip rectangle's getter is implemented differently in LCL than in VCL. VCL's implementation ensures you have a valid canvas handle when you require it. As opposed, the below is how it is implemented in LCL (for Windows):

function TCanvas.GetClipRect: TRect;
begin
  // return actual clipping rectangle
  if GetClipBox(FHandle, @Result) = ERROR then
    Result := Rect(0, 0, 2000, 2000);{Just in Case}
end;

As you can see some arbitrary rectangle is returned just in case when canvas handle is not valid - which is the case outside of the paint handler of the paint box.

You can specify the rectangle yourself to resolve:

var
  bmp : TBitmap;
  R: TRect;
begin
  ...
     R := Rect(0, 0, bmp.Width,  bmp.Height);
     bmp.Canvas.CopyRect(R, PaintBox1.Canvas, R);
     bmp.savetofile('...
  ...
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169