Image Management Tool

Does anyone have an example of using the Image Management Tool to upload images from a client? Currently using version 7.9. I found the post below, but have not been even close to successful in getting it to work.

[Image Management Tool Query]

Thanks!

from java.awt import Toolkit
from java.io import File
from org.apache.commons.io import FilenameUtils
from com.inductiveautomation.ignition.designer.gateway import DTGatewayInterface

gi = DTGatewayInterface.instance
filepath = system.file.openFile()
if filepath is not None:
	name = File(filepath).name
	javaImage = Toolkit.defaultToolkit.getImage(filepath)

	gi.uploadImage(event.source, name, "Script uploaded image", FilenameUtils.getExtension(filepath), "", javaImage.width, javaImage.height, system.file.readFileAsBytes(filepath))

Something like this might do it.

very close, after a couple minor mods, I am getting TypeError: uploadImage(): expected 9 args; got 8

from java.awt import Toolkit
from java.io import File
from org.apache.commons.io import FilenameUtils
from com.inductiveautomation.ignition.designer.gateway import DTGatewayInterface

# gi = DTGatewayInterface.instance
gi = DTGatewayInterface

filepath = system.file.openFile()

if filepath is not None:

	name = File(filepath).name

#	javaImage = Toolkit.defaultToolkit.getImage(filepath)
	javaImage = Toolkit.getDefaultToolkit().getImage(filepath)

	gi.uploadImage(event.source, name, "Script uploaded image", FilenameUtils.getExtension(filepath), "", javaImage.width, javaImage.height, system.file.readFileAsBytes(filepath))

Any stack trace on the TypeError? The call you’re using lines up with the signature I’m expecting. What Ignition version?

Version 7.9.13

Traceback (most recent call last):
  File "<event:actionPerformed>", line 18, in <module>
TypeError: uploadImage(): expected 9 args; got 8

	at org.python.core.Py.TypeError(Py.java:235)
	at org.python.core.PyReflectedFunction.throwError(PyReflectedFunction.java:209)
	at org.python.core.PyReflectedFunction.throwArgCountError(PyReflectedFunction.java:262)
	at org.python.core.PyReflectedFunction.throwError(PyReflectedFunction.java:319)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:167)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:204)
	at org.python.core.PyObject.__call__(PyObject.java:357)
	at org.python.core.PyObject.__call__(PyObject.java:361)
	at org.python.pycode._pyx4.f$0(<event:actionPerformed>:18)
	at org.python.pycode._pyx4.call_function(<event:actionPerformed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:165)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1275)
	at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:636)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.runActions(ActionAdapter.java:180)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.invoke(ActionAdapter.java:271)
	at com.inductiveautomation.factorypmi.application.binding.action.RelayInvocationHandler.invoke(RelayInvocationHandler.java:57)
	at com.sun.proxy.$Proxy35.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue.access$500(Unknown Source)
	at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)

Ignition v7.9.13 (b2019120915)
Java: Azul Systems, Inc. 9.0.7.4

# gi = DTGatewayInterface.instance
gi = DTGatewayInterface

That changes the semantics. uploadImage() is an instance method on the DTGatewayInterface class - but you’re calling it as DTGatewayInterface.uploadImage() - which is technically allowed in Python, but only if you provide an instance of self, which you don’t have in this case.
Change that line to:
gi = DTGatewayInterface.getInstance().

That fixed it…

I am working on a windows computer, tried to upload a file with extension “jpg” and it failed. Hardcoded “JPEG” instead of FilenameUtils.getExtension(filepath) and it worked.

Thanks.

Ah, yeah, there’s constants on the gateway that are matched against. In 7.9 the only valid formats are:

PNG
JPEG
GIF
BMP

You’ll have trouble with the code I posted with .bmp, I think - the width/height code won’t work, I’m pretty sure.

You got me over a big hump…

With your assistance, I got it working great in the designer, but it fails when run from a client.

Error message is

com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last):
  File "<event:actionPerformed>", line 4, in <module>
ImportError: No module named designer

Following is the script, line 4 imports DTGatewayInterface:

from java.awt import Toolkit
from java.io import File
from org.apache.commons.io import FilenameUtils
from com.inductiveautomation.ignition.designer.gateway import DTGatewayInterface
#from com.inductiveautomation.ignition.client.gateway_interface import DTGatewayInterface
import imghdr

gi = DTGatewayInterface.getInstance()

filepath = event.source.parent.getComponent('File Explorer').selectedPath
image_name = File(filepath).name

image_data = system.file.readFileAsBytes(filepath)

javaImage = Toolkit.getDefaultToolkit().getImage(filepath)

#valid image types PNG, JPEG, GIF, BMP
image_type = imghdr.what(str(filepath)).upper()

folder = "%s/" % event.source.parent.sop_id

images = gi.getImageList(event.source, folder)
new_image = True
for i in range(images.rowCount):
	if '%s%s' % (folder,image_name) == images.getValueAt(i, 'path'):
		new_image = False
		break

if new_image or system.gui.confirm('Image %s already exists for this SOP. Overwrite?' % image_name, 'Image Exists'):

	gi.uploadImage(event.source, image_name, "Image Description", image_type, folder, javaImage.width, javaImage.height, image_data)
	project.procedure.item_add(system.gui.getWindow('sop_edit').getRootContainer().getComponent('procedure'), event.source.parent.index, 20400, event.source.parent.level, '%s%s' % (folder,image_name))
	system.nav.closeParentWindow(event)

DTGatewayInterface only exists in the designer. Technically you could try sending a message over our interface from a client, but I'm not positive it'll be allowed from the client scope...

A perhaps better option that would work on both scopes would be a gateway level function in a message handler - look around this forum for IgnitionGateway/SRContext, then call getImageManager(), from which you can call the uploadImage method directly with basically the same arguments you were already supplying:

public void insertImage(String name, String desc, ImageFormat type, final String dir, byte[] input, int width, int height, int size) {

I do not understand your response “DTGatewayInterface only exists in the client”. The script is attached to a button press. In the designer, the button press works fine. It does not work when pressed from a client. Any chance I can speak to someone about this?

Support really isn’t equipped to deal with low level hacking like this. In case I didn’t make it clear enough - this isn’t a “supported” feature. You can technically make it work, using techniques I’ve described, but you’re entirely on your own if it doesn’t work.

DTGatewayInterface is a Java class that literally doesn’t exist when you’re in a client. It’s not part of the required collection of Java code to run a Vision client, so it’s not available.

Ok, I’m very close again…

I am passing all the parameters to a Gateway Message Handler, it is blowing up because I am putting the string ‘JPEG’ in the 3rd parameter which wants an ImageFormat. Can you tell me how to convert from the string to an ImageFormat, including any using or import. Thanks!

Got it.

First,

from com.inductiveautomation.ignition.gateway.images import ImageFormat

Then use: ImageFormat.JPEG (exactly like that - no quotes, etc) as the third parameter.

1 Like

You cannot believe how many variations of that I attempted. I’ll post the full solution after I clean it up.

1 Like

The following works in versin 7.9.13, but any suggestions for improvement are greatly appreciated:

Gateway Event Script \ Message named image_upload:

	from com.inductiveautomation.ignition.gateway import SRContext
	from com.inductiveautomation.ignition.gateway.images import ImageFormat
	
	context = SRContext.get()
	image = context.getImageManager()

#	1  Valid image types PNG, JPEG, GIF, BMP
	image_type = {
		'PNG' : ImageFormat.PNG,
		'JPG' : ImageFormat.JPEG,
		'JPEG': ImageFormat.JPEG,
		'GIF' : ImageFormat.GIF,
		'BMP' : ImageFormat.BMP}[payload['image_type']]

	image.insertImage(payload['image_name'], payload['image_desc'], image_type, payload['folder'], payload['image_data'], payload['width'], payload['height'], payload['size'])
	
	return

Script on the “Upload” button on the Vision Window:

from java.awt import Toolkit
from java.io import File
from org.apache.commons.io import FilenameUtils
import imghdr

filepath = event.source.parent.getComponent('File Explorer').selectedPath

payload = {}
payload['image_name'] = File(filepath).name
payload['image_desc'] = None

#  Valid image types PNG, JPEG, GIF, BMP, fix this in the message handler
payload['image_type'] = imghdr.what(str(filepath)).upper()

#  Foward slash is necessary part of folder name
payload['folder'] = "folder/"

javaImage = Toolkit.getDefaultToolkit().getImage(filepath)
payload['width']  = javaImage.width
payload['height'] = javaImage.height

size = File(filepath).length()
payload['size']   = size

payload['image_data'] = system.file.readFileAsBytes(filepath)

#  Call the gateway event script message handler, named image_upload on this project
proj = system.tag.read("[System]Client/System/ProjectName").value
status  = system.util.sendRequest(proj, 'image_upload', payload)
1 Like

The imageformat stuff could be simplified a little bit:

	image_type = ImageFormat.valueOf(payload["image_type"].upper())

Java enum classes automatically get a valueOf method that does a case sensitive string comparison and throws an exception if the value is not found.