# Canvas speed

**URL:** <https://forum.inductiveautomation.com/t/canvas-speed/8188>\
**Category:** Ignition\
**Created:** [March 20, 2014, 7:09pm UTC](https://forum.inductiveautomation.com/t/canvas-speed/8188 "2014-03-20T19:09:08Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![AJBerera](https://avatars.discourse-cdn.com/v4/letter/a/9fc29f/32.png) [@AJBerera](https://forum.inductiveautomation.com/u/AJBerera)\
**Post date:** [March 20, 2014, 7:09pm UTC](https://forum.inductiveautomation.com/t/canvas-speed/8188/1 "2014-03-20T19:09:08Z")

</div>

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](http://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?

---

<div class="post-metadata">

**Author:** ![adamaustin](https://avatars.discourse-cdn.com/v4/letter/a/5f8ce5/32.png) [@adamaustin](https://forum.inductiveautomation.com/u/adamaustin)\
**Post date:** [March 20, 2014, 7:24pm UTC](https://forum.inductiveautomation.com/t/canvas-speed/8188/2 "2014-03-20T19:24:50Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![AJBerera](https://avatars.discourse-cdn.com/v4/letter/a/9fc29f/32.png) [@AJBerera](https://forum.inductiveautomation.com/u/AJBerera)\
**Post date:** [March 28, 2014, 12:42pm UTC](https://forum.inductiveautomation.com/t/canvas-speed/8188/3 "2014-03-28T12:42:16Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![nmudge](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nmudge/32/3394_2.png) [@nmudge](https://forum.inductiveautomation.com/u/nmudge)\
**Post date:** [March 28, 2014, 3:13pm UTC](https://forum.inductiveautomation.com/t/canvas-speed/8188/4 "2014-03-28T15:13:43Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![adamaustin](https://avatars.discourse-cdn.com/v4/letter/a/5f8ce5/32.png) [@adamaustin](https://forum.inductiveautomation.com/u/adamaustin)\
**Post date:** [March 28, 2014, 3:21pm UTC](https://forum.inductiveautomation.com/t/canvas-speed/8188/5 "2014-03-28T15:21:35Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![chi](https://avatars.discourse-cdn.com/v4/letter/c/0ea827/32.png) [@chi](https://forum.inductiveautomation.com/u/chi)\
**Post date:** [March 28, 2014, 3:39pm UTC](https://forum.inductiveautomation.com/t/canvas-speed/8188/6 "2014-03-28T15:39:48Z")

</div>

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:

```auto
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'
```

---

<div class="post-metadata">

**Author:** ![adamaustin](https://avatars.discourse-cdn.com/v4/letter/a/5f8ce5/32.png) [@adamaustin](https://forum.inductiveautomation.com/u/adamaustin)\
**Post date:** [March 28, 2014, 4:04pm UTC](https://forum.inductiveautomation.com/t/canvas-speed/8188/7 "2014-03-28T16:04:35Z")

</div>

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

```auto
scaledImage = None
```

repaint

```auto
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)
```

---

<div class="post-metadata">

**Author:** ![adamaustin](https://avatars.discourse-cdn.com/v4/letter/a/5f8ce5/32.png) [@adamaustin](https://forum.inductiveautomation.com/u/adamaustin)\
**Post date:** [March 31, 2014, 3:00pm UTC](https://forum.inductiveautomation.com/t/canvas-speed/8188/8 "2014-03-31T15:00:22Z")

</div>

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:

```auto
#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)

```
