The Paintable Canvas is a very powerful advanced component that allows displaying custom graphic content using the Java Graphics2D API. Basic information about the component is available in the Appendix/Components/Misc/Paintable Canvas section of Ignition user manual. This article offers additional use cases and examples.
The prerequisites for working with the examples below are:
- Familiarity with scripting in general, and with event scripting in Ignition in particular.
- At least a basic familiarity with the Java programming language and with using Java in Jython scripting.
- An ability to read and work with Java API documentation.
Contents:
1. Working with Existing Images ¶
One of the most common use cases for the Paintable Canvas component is displaying images retrieved either from a database table using a SQL query, or from a file server using the image URL.
Displaying an Image Stored in a Database Table ¶
Purpose | Code |
---|---|
Retrieve an image stored as a BLOB in a SQL database, and display it using the Paintable Canvas component. Note: the query in this example relies on a specific SQL table structure. Make sure to adjust the query, including table and column names, as well as any filtering, to match your table structure and needs. |
from javax.imageio import ImageIO from java.io import ByteArrayInputStream # 1. See if the image is cached; if not, load it from the database bytes = event.source.getClientProperty("img-bytes-cached") if not bytes: query = "SELECT image_blob FROM imagestore limit 1" bytes = system.db.runScalarQuery(query) event.source.putClientProperty("img-bytes-cached",bytes) # 2. Read the image from the bytes image = ImageIO.read(ByteArrayInputStream(bytes)) # 3. Draw the image event.graphics.drawImage(image,0,0,event.source) |
Displaying an Image from a URL ¶
Purpose | Code |
---|---|
Retrieve an image from a URL and display it using the Paintable Canvas component. The URL can be hard-coded, or read from a custom property. |
from java.net import URL from javax.imageio import ImageIO # 1. Obtain the URL string. imageURL = "your/URL/here" # 2. Create a Java URL object from the URL string url = URL(imageURL) # 3. Read the image at the URL image = ImageIO.read(url) # 4. Display the image, aligned to the top left corner event.graphics.drawImage(image, 0, 0, event.source) |
Adjusting Image Size ¶
It is quite likely that the original image you are trying to display does not have the same size / dimensions as the size of the Paintable Canvas component you want to display it in. If that is the case, you have two options:
- Make no adjustments and display the image in its original size.
If the image is larger than the Paintable Canvas component, the image will be cropped; if the image is smaller, it will only partially fill the component. - Scale the image using the
scale
method of the Graphics2D object. Please refer to the section on scaling and zooming for examples.
2. Drawing Custom Images ¶
In addition to retrieving and displaying images, it is also possible to draw geometric primitives and arbitrary shapes on the Paintable Canvas. This includes points, lines, curves, ellipses, arcs, rectangles, paths, and any combinations of the above, creating a completely custom image. The default example on the repaint
event handler of the Paintable Canvas is a great illustration of this functionality, showing how to draw a motor. Below are examples illustrating some of that functionality.
Purpose | Code |
---|---|
Draw a rectangle Other shapes, lines, curves can be drawn in a similar way. Please see this tutorial from Oracle for details. |
from java.awt import Color from java.awt.geom import Rectangle2D # 1. Specify the rectangle's size in pixels width = 100 height = 50 # 2. Specify its position, in pixels, relative to the top left edge of the component x = 20 y = 30 # 3. Create the rectangle using the specs from steps 1 and 2. rectangle = Rectangle2D.Float( x, y, width, height) # 4. Set the color and draw the rectangle g = event.graphics g.setColor(Color.GREEN) g.draw(rectangle) |
Draw an arbitrary shape based on the coordinates stored in a dataset. This example implies a dataset with each row storing the X and Y coordinates of a single point. The columns in this case are called "xCoord" and "xCoord", respectively. Please see this tutorial from Oracle for more information on drawing arbitrary shapes. |
from java.awt import Color from java.awt.geom import GeneralPath # 1. Get the shape coordinates from a dataset coordinates = event.source.points # 2. Create an arbitrary shape shape = GeneralPath() # 3. Create a starting point from the 0-th row of the dataset shape.moveTo(coordinates.getValueAt(0, "xCoord"), coordinates.getValueAt(0, "yCoord")) # 4. Iterate through the rows of coordinates and draw the lines for rowNdx in range(1, coordinates.rowCount): shape.lineTo(coordinates.getValueAt(rowNdx, "xCoord"), coordinates.getValueAt(rowNdx, "yCoord")) # 5. Close up the shape shape.closePath() # 6. Set the color and draw the shape. g = event.graphics g.setColor(Color.GREEN) g.draw(shape) |
Additionally, you can specify the line (outline) color, stroke style (e.g. use a dashed line), fill color and gradient for the shape. Please see this tutorial from Oracle for more information.
3. Drawing Text ¶
For the cases where it is necessary to display text on the Paintable canvas (by itself, or to label images) Java Graphics2D library conveniently provides the drawString
method so you do not have to trace the letters using curves, etc. yourself. The method takes the String to draw and the X and Y coordinates of the lower left point of the string, in pixels, relative to the top left of the Paintable Canvas component.
Purpose | Code |
---|---|
Draw text The string given to the drawString method can be specified as a literal, obtained from a custom property, or put together programmatically. |
from java.awt import Color from java.awt.geom import GeneralPath # 1. Specify the string to display string = "Some string to display." # 2. Specify X and Y coordinates of the lower left point for the displayed text startingX = 50 startingY = 10 #3. Set the color and draw the string g = event.graphics g.setColor(Color.BLUE) g.drawString(string, startingX, startingY) |
4. Scaling, Zooming, and Rotating ¶
Scaling and Zooming ¶
Purpose | Code |
---|---|
Scale an image by a factor of 2 (zoom to 200%). |
# 1. Get a reference to the java.awt.Graphics2D object g = event.graphics # 2. Define the scale factor, and scale the image horizontally and vertically scaleFactor = 2.0 g.scale(scaleFactor, scaleFactor) # 3. Draw the image, aligned ot the top left of the component g.drawImage(image,0,0,event.source) |
Dynamically control the zoom factor via a custom property. The example implies that the Paintable Canvas component has an Integer type custom property called "zoom" containing the zoom percentage (e.g. 200 for zooming by 200%). |
from javax.imageio import ImageIO from java.io import ByteArrayInputStream # 1. Get the image bytes from the database or cache bytes = event.source.getClientProperty("img-bytes-cached") if not bytes: bytes = system.db.runScalarQuery("SELECT image_blob FROM imagestore limit 1") event.source.putClientProperty("img-bytes-cached",bytes) # 2. Read the image from the bytes image = ImageIO.read(ByteArrayInputStream(bytes)) # 3. Get the scale factor and convert the Integer percent value to a Float scale factor scaleFactor = event.source.zoom * 0.01 # 4. Scale and draw the image g = event.graphics g.scale(scaleFactor, scaleFactor) g.drawImage(image,0,0,event.source) |
The same technique could be used to dyanmically scale an image to the size of the Paintable Canvas component, when the ratio of the image size to the component size is not known in advance.
Purpose | Code |
---|---|
Scale an image by a horizontal and vertical and factors that are calculated based on the size of the image and the size of the Paintable Canvas component. |
# 1. Get the width and height of the BufferedImage object returned from ImageIO.read call: imageW = image.getWidth() imageH = image.getHeight() # 2. Get the width and height of the Paintable Canvas component canvasW = event.width canvasH = event.height # 3. Calculate the scale factors; # Account for 1 pixel of the component's border dimensions scaleX = (canvasW-1.0) / imageW scaleY = (canvasH-1.0) / imageH # 4. Apply scaling and draw the image g = event.graphics g.scale(scaleX, scaleY) g.drawImage(image,0,0,event.source) |
Rotating ¶
Purpose | Code |
---|---|
Rotate the image based on rotation center and angle values. In this example, the rotation center coordinates and the rotation angle value are obtained from the component's custom properties. With this set up, user controls, such as sliders, can be provided to dynamically control rotation. |
from javax.imageio import ImageIO from java.io import ByteArrayInputStream # 1. Get the image bytes from the database or cache bytes = event.source.getClientProperty("img-bytes-cached") if not bytes: bytes = system.db.runScalarQuery("SELECT image_blob FROM imagestore limit 1") event.source.putClientProperty("img-bytes-cached",bytes) # 2. Read the image from the bytes image = ImageIO.read(ByteArrayInputStream(bytes)) # 3. Get the center and angle of rotation from custom propterties rotationCenterX = event.source.rotationCenterX rotationCenterY = event.source.rotationCenterY rotationAngle = event.source.rotationAngle # 4. Draw the image g = event.graphics g.rotate(rotationAngle, rotationCenterX, rotationCenterY) g.drawImage(image,0,0,event.source) |
Comments
0 comments
Please sign in to leave a comment.