How to save PNG with Canvas DrawInto

Hi everyone,

I am trying to save a centred canvas drawing to a picture, and then save the picture as a PNG on my desktop. The issue appears to be with the DrawInto command.

In the Paint event I draw some simple drawings. When pushbutton is pressed then a new empty picture is created that has 200 pixels larger than the original canvas (300 x 225) which increases to 500 x 425. Using the DrawInto command in Canvas Paint with 0,0 works correctly and draws the Canvas1 picture in the upper left of the larger picture.

When I attempt to centre the drawing by using the command with left and top values of 100, then the drawing partially cuts some of the picture.

Is there something that I am misunderstanding about the DrawInto command? I would like the picture centred in the picture (p.Graphics).

Here is the code to download it and try:

Thanks for your help and explanations :slight_smile:

Edit: Using Xojo 2020 R2.1, Windows 10

You could do that otherwise: instead of drawing in the canvas, draw in an offscreen picture. Then, you can use this picture directly (and you draw to the canvas using its Paint event: g.DrawPicture MyOffscreenPicture,0,0; you trigger the Paint event by calling Canvas.Invalidate after having drawn your picture).

Or there’s something that doesn’t suit your needs with this way?

Yes, your solution is a possibility and thanks for the suggestion. I am attempting to stay-away from drawing in an offscreen picture as it slows down drawing operations in something like canvas animation. Drawing directly to the graphics layer of the canvas is recommended by Xojo. If I were to take the occasional screen-grab and place it in a picture that can be saved, then using the DrawInto command would be ideal.

Thanks for your suggestion @Arnaud_N, as your idea will work, and is not quite what I am looking for. :slight_smile:

If you are concerned about the overhead of offscreen pictures while drawing to the screen, put your canvas paint code into a separate method that accepts the graphics object as a parameter.

This allows you to call it direct from the canvas paint event and also from the method that creates the png by creating a picture and passing it’s graphics object.

Yes, I agree that an additional method can be created and helps make it easier to keep the code clean. The problem that I run into is that the graphics object will need to be drawn into a picture file with the DrawInto command that changes the final picture.

Thanks for the good idea.

HiDPI Monitor ?

Hi Emile,

No, this is not a HiDPI monitor. That’s a good thought though.

Maybe I’ve misunderstood what you are doing.
Why do you need to use DrawInto?

If your drawing code is in a method you just create a picture, call the method with mypicvar.Graphics and then convert to PNG.

I probably wasn’t clear, my apologies Kevin. Drawing to a picture first and then drawing to the Canvas Graphics method is incredibly slow in Xojo and drawing occurs sporadically and has a low frame rate (see about frame rates and timers). Drawing should be as fast as possible, and in Xojo this means to directly draw to the graphics method in the Canvas.

Once the drawing is complete (every 1/60th of a second or so), then it would be nice for the user to press a button to save the current frame, which requires the existing canvas graphics drawing by using DrawInto. DrawInto then draws the canvas into a picture which can be saved to the computer in PNG format.

Does this help explain what and why my question about DrawInto exists?

Thanks :slight_smile:

Where is this recommended?

1 Like

i remember DrawInto use the Paint “Event”.
in this event/method everything should paint into the given picture graphics object.

Hi Eugene

Thanks for the explanation.

I guess when you say draw directly into the canvas you mean drawing into the graphics object during the paint event.

As long as can recreate an entire frame from scratch then you should still be able to avoid DrawInto. The canvas paint event would call the drawing method passing the g parameter and your button code would just recreate the same frame again but into a picture.


Maybe here ?


Eugene, I have no issue if I refactor this code so that the save dialog is not in the Paint event. Is there a reason you’re bending over backwards to do things wrong in this example?

Example 2-8 Picture

Hi Beatrix,

I can’t seem to find the area where it was recommended. I remember that after reading the recommendation that I refactored a large amount of my Canvas book code.

Hi Tim,

I just tried many ways to make the DrawInto command work, thats all. Instead of refactoring many lines of code in a large program, I would have rather added a single DrawInto line to make this happen. Since the DrawInto command does not seem to work as expected, then I will make a workaround and refactor most of my drawing code (Shrug).

Its kind-of the other way around, I am trying to use less code to make it right. Instead, I will refactor a few hundred lines of code in another program to workaround the issues with the DrawInto command.

Its all good, just thought it would be easier, thats all. The example program was made to just show the essence of what the DrawInto program was doing, no biggie.

Here is one of the many modified versions that have been created where the canvas drawing is complete and then the DrawInto command is called post-drawing. My apologies if adding the code to save the PNG picture was causing confusion.

The same logical error occurs where the canvas drawing is modified and is not moved according to the DrawInto properties according to the left and top parameter values.

Warm regards.

Ah I missed the problem before. This new example helped me see it.

These results are absolutely wild.

1 Like

Its a bug introduced in 2018r1, probably related to 51371 - DrawInto no longer crashes when passed a clipped graphics. A paint is called an additional time with the graphics object passed along which corrupts it.

With your project altered for API1 it works as expected in 2017r2.1.

The double canvas paint is also a legacy bug from a long long time ago.


Thanks for the help Julian, much appreciated.

Ok, going back to a working version of 2017 r2.1 is the answer.

Edit: It should be 2017 r2.1 not 2018 r1.