Question Akshay Pandey · Jul 12, 2021

Convert base64 encoded stream into TIF file

Hi All,

I have a requirement where I have to create a TIF file from base64 encoded string comes in HL7 message.

I am reading content and writing to  %Stream.FileBinary after decoding and using  ..Adapter.PutStream ( EnsLib.File.OutboundAdapter) to create a file at operation. the file is getting created but its corrupted.

IS this even possible in cache? what is the correct way of doing this?

$ZV: IRIS for Windows (x86-64) 2020.1

Comments

Julius Kavay · Jul 12, 2021

The possibilities to get a corrupted file are:

- you do not read the (Base64) encoded file in chunks of N*4 (where N is an integer)
- your stream wasn't rewinded before starting with reading
- your (incoming) stream is (already) corrupted (but this would in some cases trigger an error in Base64Decode() method). 

Just for a test, try this

str = is your incoming Base64 stream

set filename = "test.tiff"
open filename:"nwu":1
if '$test write "Can't open",! quit

do str.Rewind()
use file
while 'str.AtEnd { write $system.Encryption.Base64Decode(str.Read(32000)) } // 32000 = 4 * 8000
close file

If the incoming stream is not corruoted, the right now created tiff file should be readable

0
Dmitry Maslennikov  Jul 13, 2021 to Julius Kavay

One more possibility is that the input Base64 stream has line breaks, which have to be omitted. And just read correct length would not be enough, it needs to remove all line breaks, truncate to the closest divisible by 4 length, and using the left tail with the next iteration. 

Periodically I see, that some systems may replace symbols such as "+" or "/" in Base64 with something like URL compatible.

0
Akshay Pandey  Jul 13, 2021 to Dmitry Maslennikov

Yes I am doing that, below is the code I am using 

    Set obj=##class(%Stream.FileBinary).%New()
    Set input = ""
For i=1:1:$L(obx5,"\.br\")
    {
        Set decodeline=$system.Encryption.Base64Decode($P(obx5,"\.br\",i))
        Set input = input_decodeline
    }

    Do obj.Write(input)

0
Julius Kavay  Jul 13, 2021 to Akshay Pandey

You are sure, for each and every $P(obx5,"\.br\",i) the equation $L($P(obx5,"\.br\",i))#4=0 holds?

0
Akshay Pandey  Jul 13, 2021 to Julius Kavay

no I am not sure about that

0
Julius Kavay  Jul 13, 2021 to Akshay Pandey

According to your code,  the variable obx5 contains the base64 encoded tiff image. There is one thing I do not understand: what are those "\.br\" char-sequences, how they came into the base64 stream?

Anyway, I suppose they are OK (those "\.br\"s), so put all those pieces together and decode all at once:

set input = ""
for i=1:1:$L(obx5,"\.br\") { set input = input _ $P(obx5,"\.br\",i)) }

Do obj.Write($system.Encryption.Base64Decode(input))

Now you should have a correct decoded image, provided, the obx5 variable really contains the original base64 encoded tiff image with randomly inserted "\.br\" chars (for whatever reason).

0
Jeffrey Drumm  Jul 13, 2021 to Julius Kavay

The variable obx5 most likely refers to the OBX:5 field of an HL7 message, which is normally used for narrative or image result data in healthcare. \.br\ is a commonly used mechanism for representing line breaks in formatted text data. Why they're included in a base64 string/stream is a mystery, but I've seen stranger.

0
Akshay Pandey  Jul 14, 2021 to Jeffrey Drumm

I think the reason is because of file size my input message.

HL7 file size is 1mb, this code works fine for small messages

0
Jeffrey Drumm  Jul 14, 2021 to Akshay Pandey

The maximum string length for HL7 fields in Health Connect/IRIS for Health is something like 3.6MB; larger than that, the field itself is represented as a stream. You may want to look into the stream methods for accessing fields for your use case.

0
Julius Kavay  Jul 13, 2021 to Dmitry Maslennikov

Ach, the linebreaks, good point,  спасибо!

0