Question
Akshay Pandey · Jul 12

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
00
2 0 10 106
Log in or sign up to continue

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

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.

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)

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

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).

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.

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

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

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.

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