Canvas speed

I have the following scenario.
I am viewing an image stored in my database using the canvas.

I have the following code inside my repaint event:

[code]from javax.imageio import ImageIO
from java.io import ByteArrayInputStream
partID = event.source.parent.selectedID
picID = event.source.parent.picID

databasePic = system.db.runQuery(“SELECT Picture FROM PartsPictureTemp WHERE partID = ‘%s’ AND whichPicture = %i” %(partID,picID))
if databasePic:
bytes = databasePic[0][0]
try:
bais = ByteArrayInputStream(bytes)
image = ImageIO.read(bais)
bais.close()
####BEGIN SCALED IMAGE####
scaledImage = image.getScaledInstance(300,-1,0)
event.graphics.drawImage(scaledImage, 0, 0, event.source)
####END SCALED IMAGE####
except:
event.graphics.drawString(‘Add Image’, 10, 10)[/code]

This is incredibly slow.
Is there any way to reduce the transactions?
This is querying a file every repaint… so every few milliseconds?

Yea, I noticed that, BigSchottkyD. Sorry about that. I haven’t had a chance to look into it… maybe you can store the scaled data in a byte stream of some kind?

I wonder if I could compress the images somehow before storing them into my table as a max varbinary into SQLSERVER.

The bottleneck could be the database query. Is the database query fast? If not add an index on the PartID and/or the whichPicture column.

You might consider executing the database query sometime before you have to display the image and storing the image bytes somewhere in the client, perhaps in a Python module variable.

Then when you need to display the image read the bytes from where you stored them in the client and display the image.

I was having the same problem when loading the image from a file location, too. I think it is because the repaint is happening every 250ms (or whatever) and loading and resizing the image is CPU intensive, or at least causing Ignition client to respond slowly to user interaction.

Hey, maybe you could wrap the entire repaint functionality in an “invokeAsynchronous” function?

Maybe a silly question, but why are you reloading the image data on every repaint?
I’m using something very similar and have a custom Dataset property (named ImageBytes) defined for the canvas. The SQL query to get the image data is a SQL Query property binding.

In the repaint event i access the custom property:

if event.source.ImageBytes.rowCount > 0:
	bytes = event.source.ImageBytes.getValueAt(0, 0)
else:
	bytes = None
   
if bytes:
	... your code here
else:
	... paint a string like 'no image data available'

Yea, I found something similar that worked for my test project (I haven’t error-corrected this modification of the code, but this should be close):

app.image

scaledImage = None

repaint

from javax.imageio import ImageIO
from java.io import ByteArrayInputStream
partID = event.source.parent.selectedID
picID = event.source.parent.picID

scaledImage = None
if not app.image.scaledImage:
   databasePic = system.db.runQuery("SELECT Picture FROM PartsPictureTemp WHERE partID = '%s' AND whichPicture = %i" %(partID,picID))
   if databasePic:
      bytes = databasePic[0][0]
   try:
      bais = ByteArrayInputStream(bytes)
      image = ImageIO.read(bais)
      bais.close()
      ####BEGIN SCALED IMAGE####
      scaledImage = image.getScaledInstance(300,-1,0)
      app.image.scaledImage = scaledImage
      ####END SCALED IMAGE####
   except:
      event.graphics.drawString('Add Image', 10, 10)
else:
   scaledImage = app.image.scaledImage

if scaledImage:
   event.graphics.drawImage(scaledImage, 0, 0, event.source)

Let me clarify my statement: I tested using my test code which works fine, even with multiple users browsing multiple images:

I tried to update your code with my changes, but I haven’t tested the modifications I made to your code.

My code:

#def invokeAsynch(event=event):
if app.image.scaledImage == None:
	import system
	from javax.imageio import ImageIO
	from java.awt.image import BufferedImage
	from java.net import URL
	from java.io import File, ByteArrayOutputStream
	
	scaledFileName = "C:/users/public/scaled.jpg"
	#if event.source.scaledFileName:
	#	url = event.source.scaledFileName
	#	imageStream = URL(url)
	#	scaledImage = ImageIO.read(imageStream)
	#else:
	url = event.source.fileName
	imageStream = URL(url)
	image = ImageIO.read(imageStream)
	scaledImage = image.getScaledInstance(320,-1,0)
	app.image.scaledImage = scaledImage
	#	bimage = BufferedImage(scaledImage.getWidth(),scaledImage.getHeight(),BufferedImage.TYPE_INT_ARGB)
	#	bimage.getGraphics().drawImage(scaledImage,0,0,None)
	#	#f = File(scaledFileName)
	#	baos = ByteArrayOutputStream()
	#	ImageIO.write(bimage, scaledFileName, baos)
	#	system.file.writeFile(scaledFileName, baos.toByteArray())
	#	event.source.scaledFileName = "file:///" + scaledFileName
	event.source.paint = 1
else:
	scaledImage = app.image.scaledImage
event.graphics.drawImage(scaledImage, 0, 0, event.source)
#system.util.invokeAsynchronous(invokeAsynch)
#system.util.invokeLater(invokeAsynch)