# ImageIO.read fails to read ByteArrayInputStream for image

**URL:** <https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737>\
**Category:** Ignition\
**Created:** [March 1, 2017, 2:42pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737 "2017-03-01T14:42:06Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![caitlinf](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@caitlinf](https://forum.inductiveautomation.com/u/caitlinf)\
**Post date:** [March 1, 2017, 2:42pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/1 "2017-03-01T14:42:06Z")

</div>

Hi there,

I am trying to print an image onto a Paintable Canvas component (named “tape\_image”) by passing the image bytes (called “imageData”) as a string type custom property on it. Converting the String to a ByteArrayInputStream works, but when calling ImageIO.read on that returns null. Why could this be happening?

Paintable Canvas repaint script:

[code]from javax.imageio import ImageIO  
from [java.io](http://java.io) import ByteArrayInputStream

width = event.source.getWidth()  
height = event.source.getHeight()

bais = ByteArrayInputStream(event.source.imageData)  
print bais.available()  
image = ImageIO.read(bais) #error here, image = null  
print image  
bais.close()

finalWidth = width  
finalHeight = height

imgRatio = float(image.getWidth())/float(image.getHeight())

```
	#-If Image Ratio exists, determine final width and height to fit canvas-

```

if (imgRatio \> 0):  
finalWidth = int(height \* imgRatio)  
if (finalWidth \> width):  
finalWidth=width  
finalHeight = int(finalWidth / imgRatio)

```
	#Center the picture on the canvas

```

y = (height-finalHeight) / 2  
x = (width-finalWidth) / 2

g = event.graphics  
#-Draw the Image on the canvas-  
g.drawImage(image,x,y,finalWidth,finalHeight,event.source)  
[/code]

Button that uploads the image data script:

`path = system.file.openFile()
if path != None:
   bytes = system.file.readFileAsBytes(path)
   event.source.parent.getComponent("tape_image").imageData = bytes`

print results and error from testing (uploading image of strawberry):

`7748437 (result from printing bais.available())
None (result from printing "image")
09:25:21.300 [AWT-EventQueue-2] ERROR com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter - <HTML>Error executing script for event:&nbsp;<code><b>repaint</b></code><BR>on component:&nbsp;<code><b>tape_image</b></code>.
com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last):
  File "<event:repaint>", line 18, in <module>
AttributeError: 'NoneType' object has no attribute 'getWidth'
...
...
...
...
`

---

<div class="post-metadata">

**Author:** ![KathyApplebaum](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kathyapplebaum/32/7261_2.png) [@KathyApplebaum](https://forum.inductiveautomation.com/u/KathyApplebaum)\
**Post date:** [March 1, 2017, 2:49pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/2 "2017-03-01T14:49:44Z")

</div>

If you wrap the call to system.file.readFileAsBytes in a try-catch block, you can print the error that’s returned and get some small clue about why it’s failing.

---

<div class="post-metadata">

**Author:** ![caitlinf](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@caitlinf](https://forum.inductiveautomation.com/u/caitlinf)\
**Post date:** [March 1, 2017, 3:06pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/3 "2017-03-01T15:06:09Z")

</div>

Hi Kathy, thanks for your reply.

I have tried that but the it seems that the call to readFileAsBytes succeeds as the image data is successfully transferred to the custom property I made on the paintable canvas. I also tried surrounding my call to ImageIO.read with a try-catch but no errors were thrown inside (the read simply creates a null image). Is there any way I can get some sort of debug or trace info about the execution of ImageIO.read?  
 ![](https://us1.discourse-cdn.com/inductiveautomation/original/2X/b/ba8331ea921c4b380cf5f1e0b782ca3f9b33d030.JPG)

---

<div class="post-metadata">

**Author:** ![KathyApplebaum](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kathyapplebaum/32/7261_2.png) [@KathyApplebaum](https://forum.inductiveautomation.com/u/KathyApplebaum)\
**Post date:** [March 1, 2017, 3:08pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/4 "2017-03-01T15:08:31Z")

</div>

No, there are no loggers to turn on. It pretty much succeeds or fails.

I’m a bit confused, though, because what you described in your reply doesn’t match up with the error you posted in your first message, where you said you got a null value.

---

<div class="post-metadata">

**Author:** ![caitlinf](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@caitlinf](https://forum.inductiveautomation.com/u/caitlinf)\
**Post date:** [March 1, 2017, 3:24pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/5 "2017-03-01T15:24:23Z")

</div>

Sorry about that, I’ve edited the code to be more clear. The error happens in the first script I posted, on the call ImageIO.read(bais), where bais is my byteArrayInputStream created from the custom string property that is passed the bytes from the call to readFileAsBytes. It seems that readFileAsBytes succeeds, ByteArrayInputStream succeeds (since I am able to print bais.available() which tells me how many more bytes are available in the stream), but ImageIO.read returns null when it should be creating a BufferedImage object.  
I posted the additional script just in case my method of passing data (via custom properties) is incorrect.

Is there a size limit on custom string properties? perhaps some trailing data has been cut off?

---

<div class="post-metadata">

**Author:** ![caitlinf](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@caitlinf](https://forum.inductiveautomation.com/u/caitlinf)\
**Post date:** [March 1, 2017, 3:47pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/6 "2017-03-01T15:47:15Z")

</div>

I’ve checked, and there does seem to be some issue with the data sizes. The size of the image is 5,735,855 bytes. The size of the byte array returned by readFileAsBytes is 5,735,855 bytes, so all seems well until I pass the byte array to the custom property imageData. When I call the length of imageData, the size is 7,748,437 bytes. Really strange…

---

<div class="post-metadata">

**Author:** ![abishur](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/abishur/32/9096_2.png) [@abishur](https://forum.inductiveautomation.com/u/abishur)\
**Post date:** [March 1, 2017, 4:23pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/7 "2017-03-01T16:23:28Z")

</div>

So as you guessed, the string property has an upper limit (edit: I stand corrected on this, see pturmel’s response below). The way to get around this is to create a custom method which has a parameter that accepts the bytes directly. I have un-creatively called this “redraw”. Put the following code in “redraw” Note, I modified the “g.drawImage” for testing purposes, you’ll have to modify this to fit your scaling needs.

Name: redraw  
Parameters: bytes

[code]from [java.io](http://java.io) import ByteArrayInputStream  
from javax.imageio import ImageIO

```
width = self.getWidth()
height = self.getHeight()

bais = ByteArrayInputStream(bytes)
print bais.available()
image = ImageIO.read(bais) #error here, image = null
print image
bais.close()   

finalWidth = width
finalHeight = height
    

imgRatio = float(image.getWidth())/float(image.getHeight())
     
      #-If Image Ratio exists, determine final width and height to fit canvas-
if (imgRatio > 0):
   finalWidth = int(height * imgRatio)
   if (finalWidth > width):
      finalWidth=width
      finalHeight = int(finalWidth / imgRatio)                 
      
      #Center the picture on the canvas
y = (height-finalHeight) / 2
x = (width-finalWidth) / 2
     
g = self.graphics
#-Draw the Image on the canvas-
g.drawImage(image,0,0,100,100,self)
    #store the file you uploaded into the paintable canvas so it won't disappear when it repaints itself
self.putClientProperty("img-bytes-cached",bytes) 

```

[/code]

Then put the following in the repaint function, again this is just the basic form, make sure to edit it so you get the current height/width and pass that back into the drawImage method or else the image will scale to its full size when it is repainted.

[code]from javax.imageio import ImageIO  
from [java.io](http://java.io) import ByteArrayInputStream

bytes = event.source.getClientProperty(“img-bytes-cached”)  
if bytes:  
image = ImageIO.read(ByteArrayInputStream(bytes))  
event.graphics.drawImage(image,0,0,event.source)[/code]

Then change your button code to:

`path = system.file.openFile()
if path != None:
   bytes = system.file.readFileAsBytes(path)
   event.source.parent.getComponent("tape_image").redraw(bytes)`

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 1, 2017, 4:34pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/8 "2017-03-01T16:34:15Z")

</div>

Unlike python2, jython is more like python3 when dealing with byte arrays. Assigning bytes to a string type will “decode” the bytes into 16-bit unicode characters. Fragments of your array are being extended to 16-bits and fragments that make a valid unicode sequence (probably intepreted as utf8) are being expressed directly. Nearly doubling the size is the natural result.  
You simply cannot use a String custom property to hold your raw bytes. Technically, you need a property with java type “array of bytes”. The properties customizer doesn’t offer that data type, but you can programmatically create one in the designer. This isn’t documented and if you store anything in a property that doesn’t serialize, you can break your project and the designer. [This post](https://inductiveautomation.com/forum/viewtopic.php?f=70&t=16186) and the [this follow-up post](https://inductiveautomation.com/forum/viewtopic.php?f=72&t=16198) might help you.  
I personally wouldn’t use abishur’s suggestion, as there’s an awful lot of data manipulation going on in repaint events – events that need to be blistering fast and really should not reference anything outside the component.

---

<div class="post-metadata">

**Author:** ![abishur](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/abishur/32/9096_2.png) [@abishur](https://forum.inductiveautomation.com/u/abishur)\
**Post date:** [March 1, 2017, 4:41pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/9 "2017-03-01T16:41:28Z")

</div>

Very cool to know about the array of bytes.

The method I recommend was taken from the “[Working with the Paintable Canvas Componen](https://support.inductiveautomation.com/index.php?/Knowledgebase/Article/View/110/0/working-with-the-paintable-canvas-component)t” page in the IA knowledge base.

To my knowledge, it is not referencing anything outside the component itself in the repaint script I listed. event.source.getClientProperty should be getting a property from the canvas itself, right?

---

<div class="post-metadata">

**Author:** ![caitlinf](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@caitlinf](https://forum.inductiveautomation.com/u/caitlinf)\
**Post date:** [March 1, 2017, 5:32pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/10 "2017-03-01T17:32:35Z")

</div>

Thanks for the suggestions! The decoding explains why my resulting data was larger. I will try out the DynamicPropertyDescriptor stuff and see how that works out for me.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 1, 2017, 5:36pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/11 "2017-03-01T17:36:57Z")

</div>

Hmm. I’m going to have to revisit get/putClientProperty(). That usage is handy. I’d be inclined to stick the ImageIO.read() result in the cache, though, not the raw bytes.

---

<div class="post-metadata">

**Author:** ![caitlinf](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@caitlinf](https://forum.inductiveautomation.com/u/caitlinf)\
**Post date:** [March 1, 2017, 8:48pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/12 "2017-03-01T20:48:49Z")

</div>

I have been playing around and came across an error I don’t know how to fix. The script for my button now looks like this:

[code]from com.inductiveautomation.factorypmi.application.binding import DynamicPropertyDescriptor  
from java.nio import ByteBuffer  
import java

path = system.file.openFile()  
if path != None:  
bytes = system.file.readFileAsBytes(path)  
props = event.source.parent.getComponent(“tape\_image”).getDynamicProps  
print props  
print “setting the properties”  
property = DynamicPropertyDescriptor(“imageData”, “data for image display”, java.nio.ByteBuffer, ByteBuffer.wrap(bytes))  
print property  
props.put(“imageData”,property)  
event.source.parent.getComponent(“tape\_image”).setDynamicProps(props)  
[/code]

but this results in the following error:

[code]File “event:actionPerformed”, line 13, in   
AttributeError: ‘instancemethod’ object has no attribute ‘put’

```
at org.python.core.Py.AttributeError(Py.java:173)
at org.python.core.PyObject.noAttributeError(PyObject.java:930)
at org.python.core.PyObject. __getattr__ (PyObject.java:925)
at org.python.pycode._pyx94.f$0(<event:actionPerformed>:14)
at org.python.pycode._pyx94.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:647)
at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.runActions(ActionAdapter.java:183)
at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.invoke(ActionAdapter.java:284)
at com.inductiveautomation.factorypmi.application.binding.action.RelayInvocationHandler.invoke(RelayInvocationHandler.java:55)
at com.sun.proxy.$Proxy30.actionPerformed(Unknown Source)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

```

Caused by: org.python.core.PyException: Traceback (most recent call last):  
File “event:actionPerformed”, line 13, in   
AttributeError: ‘instancemethod’ object has no attribute ‘put’

[/code]

but the treemap returned by the call getDynamicProps does have the type \<java.lang.String,DynamicPropertyDescriptor\> so my “put” should work, shouldn’t it?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 2, 2017, 12:00am UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/13 "2017-03-02T00:00:16Z")

</div>

getDynamicProps is a method. You run it by including parenthesis on it like a function. Like so:`props = event.source.parent.getComponent("tape_image").getDynamicProps()`Also, you probably don’t want to use java.nio.ByteBuffer as your property type. Just use bytes.getClass() to use the byte array’s type.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 2, 2017, 12:03am UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/14 "2017-03-02T00:03:03Z")

</div>

One more thing: creating a dynamic property descriptor should only be done once, in the designer, to add the property to your object. Don’t keep creating and adding the property in your client code. Once you’ve created the property with the type you want, just read it and assign to it like any other custom property.

---

<div class="post-metadata">

**Author:** ![caitlinf](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@caitlinf](https://forum.inductiveautomation.com/u/caitlinf)\
**Post date:** [March 2, 2017, 2:43pm UTC](https://forum.inductiveautomation.com/t/imageio-read-fails-to-read-bytearrayinputstream-for-image/12737/15 "2017-03-02T14:43:22Z")

</div>

okay, thanks for all the help 🙂
