Canvas : Scaled image and repaint event

Hello all,

I’m trying to display a scaled image in a canvas. I found several code examples on the forum and used them (thank you for sharing, by the way).

Here is the problem I meet:
When I display the “raw” image (not scaled), everything works fine.
When I change my code to scale the image, the image is indeed scaled and displayed BUT the repaint() method is called continuously.

See Attached Code.

When I use the very last line of the code, the repaint() method is only called once. (Only 1 “repaint” line in console)
When I use the line before instead, the method is looping. (Console filled with “repaint” lines)

Is there a way to avoid this looping behavior ?

Ignition version 7.8.2
Windows 10.

The code is joined in a file because it seems that submitting it in the message body makes the forum crash.

A couple observations:
First, you are querying for the image data in the repaint event. Don’t do that – repaint events are time-critical – all information needed must be available synchronously at all times. Create a dataset custom property and put your query there. The repaint event should just try to obtain that data from the dataset, not run the query.

Second, you aren’t checking the return value of the drawImage() method. That return value tells you if the image is fully painted. If not, the ImageObserver will be notified to paint again when more pixels are ready. Which is why you have repaint() called again. This is necessary, and should stop by itself when the image is fully displayed, as long as you are providing exactly the same image at every following repaint call. Consider using the drawImage() method that includes width & height and let it scale on its own.

Ideally, in either case, you would construct the image outside of the repaint() event after the dataset changes. There’s nowhere to put such an image at the moment that the repaint() method could easily obtain. There’s no custom property type that matches. It’s possible to programmatically create a custom property with an object type that could hold it, but IA doesn’t support this (because it can screw up project save if you aren’t careful). You would have to create a DynamicPropertyDescriptor() and add it to the component’s dynamic properties TreeMap.

Thank you very much for the detailled answer.
I’ll check this quickly.

Regards.

I finally got this to run “correctly”.

In summary, the idea is the fetch the image from a database BLOB field into a bytes array stored in a dataset (IMAGE_FROM_DB).
On change of IMAGE_FROM_DB, read the bytes as an input stream in order to convert it back to an Image, scale it, “cast” it to BufferedImage and translate it back to a byte[] to store it in another dataset (SCALED_IMAGE).

The repaint event of the Canvas uses the bytes array stored in SCALED_IMAGE, transforms it to an Image and then draw it.

I’m not sure it is the best way to accomplish this but it works as expected. The repaint event fires once on image change.

Moreover, the window can be saved correctly as image are stored in datasets as bytes arrays.

Thank you Phil for your help.