Copy Canvas to ImageView

In web app, is it possible to copy a Canvas image to an ImageView? I have a Canvas that takes a few seconds to Paint. Every time I navigate to another page then back, it redraws the Canvas again. It would be better to just take picture after first Canvas Paint is done and use that.

I am guessing it isn’t possible to do this in web app. If not, is there any way to lock a canvas after first paint?

  • Add a picture property to your WebPage or to a module.
  • In your canvas Paint event,
p = new picture(g.width,g.height,32)
  • Do the same to p.Graphics as to what you do to g

If it takes a few seconds to draw, it means you probably have a rather complex code in Paint. It would be better to move all that to a method where you prepare p once, and then simply g.Drawpicture in Paint.

Awesome, awesome, awesome. Thanks Michel. I’ll give it a try.

How do I set canvas to p? As a test, I put this in canvas.

dim p as new Picture(30,30, 32)
p.graphics.ForeColor = &cff0000
p.graphics.FillRect(0, 0, 30,30)
g.DrawPicture(p,0,0)

[quote=129887:@Ken Gish]How do I set canvas to p? As a test, I put this in canvas.

dim p as new Picture(30,30, 32)
p.graphics.ForeColor = &cff0000
p.graphics.FillRect(0, 0, 30,30)
g.DrawPicture(p,0,0)[/quote]

For whatever reason, Drawpicture does not work. However, the picture is correctly created and drawn, and it shows up fine in an Image Well :

dim p as new Picture(30,30, 32) p.graphics.ForeColor = &cFF020000 p.graphics.FillRect(0, 0, 30,30) ImageView1.picture = p

I also tried to use a window property for p, and to create the graphic outside of Paint. Then it displays fine.

You may want to create the graphic elsewhere, and use an Image Well, instead of a canvas.

That worked! Thanks Michel.

I read this thread which seems to suggest the problem has something to do with roundtrip to server? I will look into it. Not sure that thread is a related issue. If I figure it out I’ll update.

It works if you define p in the shown event of canvas too. I don’t get it.

It is probably a question of scope.

Is order always: 1st = Open, 2nd = Shown, 3rd = Paint?

Picture doesn’t have a TextAlignment method like the Canvas does. I know I can probably get text length somehow but I’d rather not (more work plus Picture method parameters are slightly different and no Shadow method). Is there any way to put Canvas drawing into Picture. This doesn’t work but it is what I want to do after the Canvas Paint event is done:

ImageView1.picture = g as picture

If not I’ll just keep going with p.Graphics

[quote=129957:@Ken Gish]Is order always: 1st = Open, 2nd = Shown, 3rd = Paint?

Picture doesn’t have a TextAlignment method like the Canvas does. I know I can probably get text length somehow but I’d rather not (more work plus Picture method parameters are slightly different and no Shadow method). Is there any way to put Canvas drawing into Picture. This doesn’t work but it is what I want to do after the Canvas Paint event is done:

ImageView1.picture = g as picture

If not I’ll just keep going with p.Graphics[/quote]

The only way to copy a graphics to another one is to copy pixel by pixel. Since Drawinto does not exist in WE, I see no way to copy the canvas to a picture.

Now, if it actually takes a few seconds to draw in Paint, I suspect you have much too much stuff in there. Not all the drawing may be exclusive to canvas. What about drawing whatever can be done on a picture the first time paint takes place, then store that picture, so the next time you do not need to do it again, and simply add the text ?

Without seeing your code or a screen, it is difficult to give you much more advice, but the idea is to store whatever you can, then use a flag to know it has been done, and do only what you must in Canvas. It could greatly speed up the process.

Just a thought but have you tried keeping the Canvas invisible, sending the draw script, and then making it visible? I know the Canvas will cache/remember what previous draw commands it has so when you send over new commands - as long as they’re appended at end it will only need to send over the new commands and not all the old commands. For this reason it’s best to render and think of the canvas in “layers”. I’m not sure if you’re fundamental problem is the browser rendering the canvas in general though. It might just be too labor intensive for their browser and there may only be browser-specific optimizations for the canvas.

Conversion is complete. I had to live without shadow, add arc width and arc height parameters, and use p.Graphics.StringWidth to center.

Problem is, no text is appearing on deployed app. Text appears final when running locally.

Picture object runs so much faster that I am thinking of doing away with canvas objects. Any idea why picture is so much faster?

Back where I started unless I can get text working in picture.

Canvas looks so much nicer with shadow and antialiased fonts. If I could get that working quicker I’d be happier. If I could just get Canvas to draw once when page first starts I think Canvas would work fine. Any ideas?

[quote=130015:@Ken Gish]Back where I started unless I can get text working in picture.

Canvas looks so much nicer with shadow and antialiased fonts. If I could get that working quicker I’d be happier. If I could just get Canvas to draw once when page first starts I think Canvas would work fine. Any ideas?[/quote]

You may want to place a label over the ImageWell. Create a style with text alignment, text color and shadow and you should be set.

Does this mean DrawString doesn’t work in picture object?

I don’t want to deal with separate labels because the page is resizable and it would be more work getting all those labels repositioned correctly.

It does work, but you said you wanted to have shadow and text alignment as available in WebCanvas Paint. A label will provide both without extra work. And perfect antialiasing, since fonts are rendered by the system.

However, text alignment is possible with Drawstring by simple calculus, and some shaddow can be obtained by drawing first the string with a grey transparent color on a lower position, then the actual drawstring in solid color. It is just a bit more involved.

I think you’re running into the browser caching the image and not displaying the modified version.

Michel - I figured out how to use StringWidth/2 to do centering and I can live without shadow. I would much rather use picture object because it is so much faster but I just can’t figure out why it isn’t displaying text.

Tim - Not sure if you are talking about picture object. I did clear cache if that’s what you are talking about. Also, it works locally (run from IDE) but not after deployed to Xojo Cloud server. It’s almost like ImageView runs on server and server has no fonts installed (just a crazy guess…I have no idea where different components run).

Brock - It suddenly hit me what you might be saying. Are you saying that each time the Paint is called, it is just drawing a new layer on top? If so, then this IS the main problem. I am trying to prevent redraw every time I go away then come back to page. If I just don’t let it repaint it just comes up blank but that’s probably just a new layer on top covering the layer underneath. The MAIN problem is that after about 10 times of leaving page then coming back the app becomes VERY SLOW. If you are right, then it’s because there are 10 separate layers in the Canvas. Not sure what to do to solve it though.

I do not understand. Where are you creating your picture ?

This works fine in an ImageWell shown event :

dim p as new picture(me.width,me.height,32) p.graphics.ForeColor = &cFF064100 p.graphics.drawstring("Hello World", 10,30) me.Picture = p