WebCanvas And Pictures

Hey guys,

In messing with a WebCanvas control, it seems to me that the WebCanvas wants to paint a picture that is a file on disk, not one in memory. If I have a picture in my project and paint that directly to my web canvas, it works fine. However, if I manipulate the picture in any way - scale it, resize it, etc. Then the canvas no longer paints the image.

So let’s take the Chart Example Xojo that is in the Examples included with Xojo. The first part of the paint event has code that looks like:

  Dim LLx As Integer = 50
  Dim LLy As Integer = g.Height-50
  Dim LRx As Integer = g.Width-50
  
  // White Background
  g.ForeColor = &cFFFFFF
  g.FillRect(0, 0, g.Width, g.Height)
  
  // Black Border
  g.PenWidth = 1
  g.ForeColor = &c000000
  g.DrawRect(0, 0, g.Width, g.Height)
  
  // Draw the logo
  Dim logoX As Integer = (g.Width-EELogo.Width)/2
  Dim logoY As Integer = (g.Height-EELogo.Height)/2
  
  g.DrawPicture(EElogo, logoX, logoY)

EElogo paints fine as EElogo is a PNG file included with the project.

However, if I do this:

  Dim LLx As Integer = 50
  Dim LLy As Integer = g.Height-50
  Dim LRx As Integer = g.Width-50
  
  // White Background
  g.ForeColor = &cFFFFFF
  g.FillRect(0, 0, g.Width, g.Height)
  
  // Black Border
  g.PenWidth = 1
  g.ForeColor = &c000000
  g.DrawRect(0, 0, g.Width, g.Height)
  
  // Draw the logo
  Dim logoX As Integer = (g.Width-EELogo.Width)/2
  Dim logoY As Integer = (g.Height-EELogo.Height)/2
  
  Dim p as Picture = EELogo
  
  Dim Aspect as Double = p.Width/p.Height
  Dim pleft as integer = ((me.Width/2)-(me.Height*Aspect/2))\\2
  
  Dim p1 as New Picture((me.Width/2),(me.Height/2))
  
  p1.graphics.DrawPicture(p,pleft,0,(me.height*aspect/2),(me.height/2),0,0,p.width,p.Height)
  
  g.DrawPicture(p1, logoX, logoY)

The picture never paints because P1 is a picture in memory NOT on disk. Is this a bug? Expected behavior?

I’m simply trying to scale the picture. In many cases, this is needed as the picture may be too large to fit in the canvas. There is no scaling capabilities in the WebGraphics.DrawPicture method. So I want to scale to another image and then paint that image. But it doesn’t work.

File a bug report with your sample. Off the top of my head, I can’t think of why this wouldn’t work.

Keep in mind that an html5 canvas will only draw the image after it has been received by the browser (as a separate request). It shouldn’t take long, but it may not show up the first time it draws. Once the image downloads, the canvas is told to refresh.

OK. I will. I wanted to make sure I was not doing something wrong.

And yes, I get the bit about downloading the image to the browser. When trying to paint a picture from memory, the image never draws. You could wait hours and it would not show up.

I’ll post feedback shortly.

( erm… I don’t want to hijack this thread but, Jon, could you answer me in the other thread so I wont let the test run forever on my server ? That would be appreciated. Thanks )

Greg - Here is the feedback…

<https://xojo.com/issue/33197>

Guy - I’ll post in the other thread - sorry.

[quote=80131:@Jon Ogden]Greg - Here is the feedback…

<https://xojo.com/issue/33197>

Guy - I’ll post in the other thread - sorry.[/quote]
Ah. You’ve got yourself into an endless loop. Create the picture outside of the paint event.

Here’s what’s going on:

Server
0. Paint Event
0. Create Image
0. DrawPicture

Browser
0. Canvas Refreshes
0. Image gets requested
0. Refresh sent to server
0. Go to Server #1

So the problem is that every time you create a new image, we can’t tell that it’s the same as the last one, so we need to send the image to the browser again and the browser is in a continuous cycle of loading images, which unfortunately manifests as a leak and will likely crash the browser after a while.

Oh. I see…

That’s pretty obscure and 100% different from the desktop. Let me try that…

Yep. In the example I posted to the feedback case, I made the “p1” picture a property of the page and moved the creation of that picture and drawing into it into the push button.

It worked just like it was supposed to.

So really the rule with painting in a canvas is to only use your FINAL picture in the paint event. Don’t do any other graphical manipulations of images in paint. Do them all outside before calling refresh/invalidate. Good tip to know. If that’s not documented anywhere, it should be…

In fact would there be a way to throw an exception if this sort of activity occurs? Maybe you can’t tell inside the framework what’s happening, but I could see this affecting people quite a bit.

Learn something new every day! :slight_smile:

So here’s the thing. When you create a new picture object and draw into it, it’s a completely new picture as far as the framework is concerned, so we must send it to the browser on the chance that it has changed. The difference is that the browser can’t draw the picture into the canvas until after it has requested and received it, which is after it has drawn everything else the first time, so we need to trigger a refresh to get it to include the picture.

Realistically this isn’t all that much different than the desktop… on the desktop, if your picture doesn’t change, creating it from scratch over and over just wastes CPU cycles.

[quote=80248:@Greg O’Lone]So here’s the thing. When you create a new picture object and draw into it, it’s a completely new picture as far as the framework is concerned, so we must send it to the browser on the chance that it has changed. The difference is that the browser can’t draw the picture into the canvas until after it has requested and received it, which is after it has drawn everything else the first time, so we need to trigger a refresh to get it to include the picture.
[/quote]

Makes sense. It’s just not something you would necessarily think of.

[quote]
Realistically this isn’t all that much different than the desktop… on the desktop, if your picture doesn’t change, creating it from scratch over and over just wastes CPU cycles.[/quote]

So are you telling me that you should not create a new picture in the paint event of a desktop app? I do it all the time. Maybe that’s bad coding practice but it’s never created a problem. Maybe I don’t do it specifically like I do here in the web as the desktop paint event can do scaling whereas the web paint event cannot. But should you avoid creating/painting new pictures in a desktop paint event as well?

Myself I found it a bit odd.

It’s like creating an object (New MyClass()) that you will override anyway in some loop, instead of creating it first outside the loop, then enter the loop then do whatever you want with your object inside the loop (even if you have to clear it up each time).

Object creation (Class instancing) is always a (relatively) heavy process whatever the language you use.

In your case, what prevent you to create your Picture at first and store it as some Property, then reuse it each time in your Paint Event ?

[quote=80263:@Guy Rabiller]Myself I found it a bit odd.

It’s like creating an object (New MyClass()) that you will override anyway in some loop, instead of creating it first outside the loop, then enter the loop then do whatever you want with your object inside the loop (even if you have to clear it up each time).

Object creation (Class instancing) is always a (relatively) heavy process whatever the language you use.

In your case, what prevent you to create your Picture at first and store it as some Property, then reuse it each time in your Paint Event ?[/quote]

Actually, I just went and took a quick look through a number of my canvases that are in regular use and I don’t see me creating new picture objects inside the paint events. I dimension picture variables but they are always sent equal to some other already created picture object. So I think what I was trying to do with the web was fairly unique so I could get the scaling I want.

There’s one canvas where I draw create a secondary picture of some text that I am drawing so that it scales properly into the canvas if it is resized. In most instances this is drawn outside the paint. I do check of this pic is Nil in the paint event and if so I create a new one but that should almost never happen unless something isn’t done right somewhere else.