How can I call a "get_screenshot" method from inside a SFC?

I wrote a method (below) for nabbing screenshots from a Vision client. It works (paired with the appropriate helper methods / gateway messageHandler for writing to a filesystem), but I want to call it from within a SFC rather than from the vision client itself and I am pretty sure it will misbehave.

Is it possible to augment this function such that it grabs the screenshots from the vision client that dispatches the SFC in the first place? Almost like a reverse messageHandler.

def get_screenshot(run_name, shot_number=None, window=None, project="tb1", ext='png'):
	from java.awt import Robot, Rectangle, GraphicsEnvironment
	from javax.imageio import ImageIO
	from java.io import ByteArrayOutputStream
	import system
	import os
	import base64

	# Define the base directory to save the screenshots
	file_dir = svc.common.work_dir(project=project, name=run_name, fs='ignition')
	print(file_dir)
	print(gateway.ensure_dir(file_dir))

	# Get all available screens
	graphics_env = GraphicsEnvironment.getLocalGraphicsEnvironment()
	screens = graphics_env.getScreenDevices()
	
	# Initialize Robot for screen capture
	robot = Robot()

	# Iterate over each screen and capture it
	for index, screen in enumerate(screens):
		# Define the bounds for the current screen
		screen_bounds = screen.getDefaultConfiguration().getBounds()
		rectangle = Rectangle(screen_bounds.x, screen_bounds.y, screen_bounds.width, screen_bounds.height)
		
		# Capture screenshot for the current screen
		screenshot = robot.createScreenCapture(rectangle)
		
		# Create a unique filename for each screen
		file_name = "{}_shot{}_screen{}".format(run_name, shot_number, index)
		file_path = file_dir + "/" + file_name + "." + ext # assume linux since this goes to gateway
		print(file_path)
		
		# Convert the BufferedImage to a Base64 string
		byte_stream = ByteArrayOutputStream()
		ImageIO.write(screenshot, ext, byte_stream)
		image_bytes = byte_stream.toByteArray()
		encoded_image = base64.b64encode(image_bytes).decode('utf-8')
		
		# Write the encoded image to the specified path on the gateway
		gateway.write_image(file_path, encoded_image, ext=ext)
	
	return file_dir  # Returns the directory where screenshots are saved

You might be able to do something like:

  • put the client session id into the parameters dict of the system.sfc.startChart call
  • when you need the screenshot eventually, use the id to target system.util.sendMessage to that client
  • the message handler in the client will then run your screenshot function
2 Likes

Thanks I will try this

I am using a system.util.invokeAsynchronous when I do this from a button -- is that necessary when calling in this manner? Followup, would I ever want to invokeAsynchronous from within a SFC?

Probably not... I don't think the message handlers run on the UI thread, which is presumably why you were doing this in the first place.

Probably not, though I will generally advise most people against using invokeAsynchronous without compelling reason :person_shrugging:

2 Likes

Fun one: it seems to not work because of a Java heap error but it isn't logging that into the gateway console. Can only see it if I engage the parent SFC via a vision client.

Do I increase the gateway allocation or the vision client allocation or both?