Rendering PNG data in perspective

Hi, I am trying to render ZPL code in my application using Labelary API. I have a image component that has binding on source prop. This binding is as follows:


The response contains PNG data but i dont know how to process them so it shows as a image. Can anyone advise please?

You probably want a script transform to turn the response from the third party into a data url: Data URLs - HTTP | MDN

I tried to convert it in similar way I did it wil images from database but I used SQL to do the base64 conversion. In this case a get a some result which seems to be invalid.

I found a thread where there is a another base64 function used for converting the data:
Signature component image to Report - Ignition Early Access - Inductive Automation Forum

I used Base64.encodeBytes() method. Now the result looks like a base64 string but it still wont render in Image component.

I was suspecting that the data the POST request returned were modified by Ignition so I tried to save the PNG data to a .png file. It seems the data are not correct and I cannot display the image file in Windows.

The code I used to get the png for saving is below:

URL = "http://api.labelary.com/v1/printers/12dpmm/labels/5.82677x8.26772/0/"

contentType = "application/x-www-form-urlencoded"
headers = {
  'Accept': 'image/png',
  'Content-Type': 'application/x-www-form-urlencoded'
}

res = system.net.httpPost(URL, 
			contentType = contentType, 
			postData = ZPL, 
			headerValues = headers, 
			throwOnError = False
		)
		
filename = system.file.saveFile("image.png")
if filename is not None:
   system.file.writeFile(filename, str(res))

That would certainly break the file. PNG contents are not strings, they are bytes.

It actually breaks sooner, because system.net.httpPost returns a String:

If the bytes are needed then system.net.httpClient must be used instead.

1 Like

Is this a same case with HTTP binding? Does it also return a string?

Hmm, I think it might be...

If you're just looking to display, I did that using an Inline Frame and the Labelary web services.

I wanted to do the same but since i cannot pass my ZPL as URL params, I have to use POST and send the ZPL as data. With that one cannot use iframe or image component.

The reason I have to use POST instead of GET is that my ZPL contains image data and the ZPL gets too long for URL.

oh, yeah, most of my labels don't use graphics, I just got one the other day that does have graphics and yeah, the IFrame didn't work. They are so few and far between I was just able to not worry about it. So will probably be reviewing this post someday assuming it all gets worked out

If allowed on your server, perhaps you can have labelary return a PDF, write it into the gateway filesystem, and have the PDF viewer render it?

That would would be plan C. I will try using the Http client as suggested and write the png data into temp file (system.file.getTempFile). Then display it using the Image component. If that doesn´t work, I will try pdf.

That´s shame, I was so happy to find a good use case for the HTTP binding.

One can use this to deal with this situation:

from org.apache.http.impl.client import HttpClients
from org.apache.http.client.methods import HttpPost
from org.apache.http.util import EntityUtils
from org.apache.http.entity import StringEntity
from java.io import ByteArrayOutputStream
from java.util import Base64


# Create an HttpClient object
httpClient = HttpClients.createDefault()
try:
    # Create a POST request to the desired URL
    request = HttpPost("http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/")

    # Set any necessary headers
    request.addHeader("Content-Type", "application/x-www-form-urlencoded")
    request.addHeader("Accept", "image/png")
    zpl = """
	^xa^cfa,50^fo100,100^fdHello World^fs^xz
	"""
	
    request.setEntity(StringEntity(zpl))
	
    # Execute the request
    response = httpClient.execute(request)
    try:
        # Get the response entity
        entity = response.getEntity()
        print 
        
        if entity is not None and str(entity.getContentType()).split(" ")[1] == "image/png":
            # Convert entity content to byte array
            buffer = ByteArrayOutputStream()
            entity.writeTo(buffer)

            # Convert byte array to Base64 string
            base64Image = Base64.getEncoder().encodeToString(buffer.toByteArray())

            print("Base64 Encoded Image: " + base64Image)
        else:
            print("The response did not contain a PNG image.")
        
        # Ensure the entity content is fully consumed
        EntityUtils.consume(entity)

    finally:
        response.close()

finally:
    httpClient.close()

Why a bunch of apache HTTP client imports over system.net.httpClient? GPT driven development?

Any non Java standard library import you use is subject to change and risks breaking on major or minor version upgrade. Using system.net.httpClient is guaranteed to be supported.

Yeah, this is GPT code. I wanted to post it here so I can get to it later.

Can it happen that IA decides not to include apache libraries in the future? I wrote jython excel library with it few days ago.

Yes, this can happen. Any time you write code against an Ignition implementation detail or Java dependency this is a risk you take.

But if they drop them, you could build an SDK module to add them back. So, not a big risk, really.

I mean... someone could, but probably not the same someone who is getting their code from ChatGPT.

4 Likes