# Transcode or decompress based on destination DICOM.

**URL:** https://discourse.orthanc-server.org/t/transcode-or-decompress-based-on-destination-dicom/2770
**Category:** Google Groups archive
**Created:** [January 18, 2022, 5:31am UTC](https://discourse.orthanc-server.org/t/transcode-or-decompress-based-on-destination-dicom/2770 "2022-01-18T05:31:21Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![Dustin\_Loftis](https://discourse.orthanc-server.org/letter_avatar_proxy/v4/letter/d/43a26b/32.png) [@Dustin\_Loftis](https://discourse.orthanc-server.org/u/Dustin_Loftis)
#### Post date: [January 18, 2022, 5:31am UTC](https://discourse.orthanc-server.org/t/transcode-or-decompress-based-on-destination-dicom/2770/1 "2022-01-18T05:31:21Z")

</div>

Hi there!

We use Orthanc 1.9.1 to route studies from a fleet of mobile US and XR techs to a central location, and then on to various destinations.

Basically, each modality talks to a local (laptop/tablet) instance of Orthanc. The mobile instance uses a LUA script with five pre-established destinations based on a string in the SCP AE title called by the modality. The mobile Orthanc auto-routes using a peer-to-peer connection over cellular back to the central Orthanc server, which auto-routes the studies to the corresponding path of the five options via DICOM. This process works without issue.

In one particular case, the technicians need to send studies to two different destinations, let’s call them A and B. Originally I was auto-routing those with the central Orthanc server in the LUA script. But destination A will only accept J2K, and destination B cannot handle J2K. Right now we’re using the modality’s settings to send them twice, uncompressed for destination A (which is transcoded to J2K by the mobile Orthanc), and JPEG compressed for destination B (which is passed on as-is.)

What I want to do is be able to receive the J2K-encoded study at the central Orthanc server, and forward it on to destination A as-is, but transcode it to either JPEG or uncompressed for destination B.

I believe from what I’ve read that it would be possible to either adjust the config.json to make the specific DICOM server always send uncompressed, or put a REST API command in the LUA to transcode the study and then send that. I haven’t been able to figure out the exact syntax to do either of these things.

– LUA Auto-routing script for Central Orthanc Server

function OnStoredInstance(instanceId, tags, metadata, origin)  
print('\*—Routing instanceId: ', instanceId)

if origin[‘Username’] ~= nil then  
– Extract the value of the “Username” tag  
local UserNameVar = string.upper(origin[‘Username’])  
– print(UserNameVar)

if string.find(UserNameVar, ‘\_DCM1’) ~= nil then  
– Send \*\_DCM1 studies to DestinationA.  
– print(‘UserNameVar includes \_DCM1’)  
SendToModality(instanceId, ‘Destination\_A’)  
print(‘P2P-’, UserNameVar, ’ - Fwd\>DestinationA.')  
end

if string.find(UserNameVar, ‘\_DCM2’) ~= nil then  
– Send \*\_DCM2 studies to both DestinationB and DestinationA.  
– print(‘UserNameVar includes \_DCM2’)  
SendToModality(instanceId, ‘DestinationB’)  
SendToModality(instanceId, ‘Destination\_A’)  
print(‘P2P-’, UserNameVar, ’ - Fwd\>DestinationA, Fwd\>DestinationB.')  
end

if string.find(UserNameVar, ‘\_DCM3’) ~= nil then  
– Send \*\_DCM3 studies to Destination\_C.  
– print(‘UserNameVar includes \_DCM3’)  
SendToModality(instanceId, ‘Destination\_C’)  
print(‘P2P-’, UserNameVar, ’ - Fwd\>DestinationC.')  
end

– if string.find(UserNameVar, ‘\_DCM4’) ~= nil then  
– – Send \*\_DCM4 studies to XXXDestination4.  
– print(‘UserNameVar includes \_DCM4’)  
– SendToModality(instanceId, ‘XXXDestination4’)  
– print(‘P2P-’, UserNameVar, ’ - Fwd\>??.')  
– end

if string.find(UserNameVar, ‘\_DCM5’) ~= nil then  
– Send \*\_DCM5 studies to Destination\_E.  
– print(‘UserNameVar includes \_DCM5’)  
SendToModality(instanceId, ‘Destination\_E’)  
print(‘P2P-’, UserNameVar, ’ - Fwd\>DestinationE.')  
end  
– print(‘Username DICOM Routing End’)  
end

if origin[‘CalledAet’] ~= nil then  
– Skip processing rules if CalledAet is nil.  
local CalledAETVar = string.upper(origin[‘CalledAet’])  
– Extract the value of the “CalledAet” DICOM tag  
– print(CalledAETVar)

if string.find(CalledAETVar, ‘\_DCM1’) ~= nil then  
– Send \*\_DCM1 studies to DestinationA.  
– print(‘CalledAETVar includes \_DCM1’)  
SendToModality(instanceId, ‘Destination\_A’)  
print(‘DICOM-’, CalledAETVar, ’ - Fwd\>DestinationA.')  
end

if string.find(CalledAETVar, ‘\_DCM2’) ~= nil then  
– Send \*\_DCM2 studies to both DestinationB and DestinationA.  
– print(‘CalledAETVar includes \_DCM2’)  
SendToModality(instanceId, ‘DestinationB’)  
SendToModality(instanceId, ‘Destination\_A’)  
print(‘DICOM-’, CalledAETVar, ’ - Fwd\>DestinationA, Fwd\>DestinationB.')  
end

if string.find(CalledAETVar, ‘\_DCM3’) ~= nil then  
– Send \*\_DCM3 studies to Destination\_C.  
– print(‘CalledAETVar includes \_DCM3’)  
SendToModality(instanceId, ‘Destination\_C’)  
print(‘DICOM-’, CalledAETVar, ’ - Fwd\>DestinationC.')  
end

– if string.find(CalledAETVar, ‘\_DCM4’) ~= nil then  
– – Send \*\_DCM4 studies to XXXDestination4.  
– print(‘CalledAETVar includes \_DCM4’)  
– SendToModality(instanceId, ‘XXXDestination4’)  
– print(‘DICOM-’, CalledAETVar, ’ - Fwd\>??.')  
– end

if string.find(CalledAETVar, ‘\_DCM5’) ~= nil then  
– Send \*\_DCM5 studies to Destination\_E.  
– print(‘CalledAETVar includes \_DCM5’)  
SendToModality(instanceId, ‘Destination\_E’)  
print(‘DICOM-’, CalledAETVar, ’ - Fwd\>DestinationE.')  
end  
– print(‘AETitle DICOM Routing End’)  
end

– This Delete is to keep Orthanc clean. Uncomment when not testing.  
Delete(instanceId)  
print(‘Done —\*’)

end

---

<div class="post-metadata">

### Author: ![Alain\_Mazy1](https://discourse.orthanc-server.org/letter_avatar_proxy/v4/letter/a/839c29/32.png) [@Alain\_Mazy1](https://discourse.orthanc-server.org/u/Alain_Mazy1)
#### Post date: [January 18, 2022, 10:38am UTC](https://discourse.orthanc-server.org/t/transcode-or-decompress-based-on-destination-dicom/2770/2 "2022-01-18T10:38:03Z")

</div>

Hi Dustin,

Unfortunately, the /modalites/{id}/store API route does not support the “Transcode” field (the /peers/{id}/store route does !) so you can not force the transfer syntax for a specific C-Store

What are your configurations wrt ?

- [DicomScuPreferredTransferSyntax](https://hg.orthanc-server.com/orthanc/file/tip/OrthancServer/Resources/Configuration.json#l426)
- [AllowTranscoding](https://hg.orthanc-server.com/orthanc/file/tip/OrthancServer/Resources/Configuration.json#l394) for destination A & B

Another option is to download a modified version of the instance (there, you can use the “Transocode” field: [https://book.orthanc-server.com/users/anonymization.html#id3](https://book.orthanc-server.com/users/anonymization.html#id3)) and then use the “/modalities/{id}/store-straight” route to push it. You can get some inspiration from this script: [https://bitbucket.org/osimis/orthanc-setup-samples/src/master/lua-samples/sanitize-and-forward.lua](https://bitbucket.org/osimis/orthanc-setup-samples/src/master/lua-samples/sanitize-and-forward.lua)

HTH,

Alain.

---

<div class="post-metadata">

### Author: ![Dustin\_Loftis](https://discourse.orthanc-server.org/letter_avatar_proxy/v4/letter/d/43a26b/32.png) [@Dustin\_Loftis](https://discourse.orthanc-server.org/u/Dustin_Loftis)
#### Post date: [January 18, 2022, 8:08pm UTC](https://discourse.orthanc-server.org/t/transcode-or-decompress-based-on-destination-dicom/2770/3 "2022-01-18T20:08:00Z")

</div>

Thank you for responding!

Based on that, since we’re using Orthanc Peers on the mobile Orthanc instances, we could theoretically transcode them there differently for each peer? That would still be sending the studies over the mobile network twice, but what would the syntax be for that?

Right now the peers list in the orthanc.json on a mobile unit looks like this:

“Central Server\_DCM1” : [“[https://dcm.domain.com](https://dcm.domain.com)”, “USER\_DCM1”, “” ],  
“Central Server\_DCM2” : [“[https://dcm.domain.com](https://dcm.domain.com)”, “USER\_DCM2”, “” ],  
“Central Server\_DCM3” : [“[https://dcm.domain.com](https://dcm.domain.com)”, “USER\_DCM3”, “” ],  
“Central Server\_DCM4” : [“[https://dcm.domain.com](https://dcm.domain.com)”, “USER\_DCM4”, “” ],  
“Central Server\_DCM5” : [“[https://dcm.domain.com](https://dcm.domain.com)”, “USER\_DCM5”, “” ]

And the LUA routing script on each unit looks like this:

function OnStoredInstance(instanceId, tags, metadata, origin)  
print((origin[‘CalledAet’]), (instanceId), (‘OnStoredInstance’))  
– PrintRecursive(origin)

local CalledAETVar = string.upper(origin[‘CalledAet’])  
– Extract the value of the “CalledAet” DICOM tag

if origin[‘CalledAet’] ~= nil then  
– Skip processing rules if CalledAet is nil.  
print(CalledAETVar)

if string.find(CalledAETVar, ‘\_DCM1’) ~= nil then  
– Send \_DCM1 studies to Destination 1.  
print(‘Routing to [DCM.DOMAIN.COM](http://DCM.DOMAIN.COM) Destination 1’)  
SendToPeer(instanceId, ‘CentralServer\_DCM1’)  
print(‘SendToPeer - Destination 1 - done…’)  
end

if string.find(CalledAETVar, ‘\_DCM2’) ~= nil then  
– Send \_DCM2 studies to Destination 2.  
print(‘Routing to [DCM.DOMAIN.COM](http://DCM.DOMAIN.COM) Destination 2’)  
SendToPeer(instanceId, ‘CentralServer\_DCM2’)  
print(‘SendToPeer - Destination 2 - done…’)  
end

if string.find(CalledAETVar, ‘\_DCM3’) ~= nil then  
– Send \_DCM3 studies to Destination 3.  
print(‘Routing to [DCM.DOMAIN.COM](http://DCM.DOMAIN.COM) Destination 3’)  
SendToPeer(instanceId, ‘CentralServer\_DCM3’)  
print(‘SendToPeer - Destination 3 - done…’)  
end

if string.find(CalledAETVar, ‘\_DCM4’) ~= nil then  
– Send \_DCM4 studies to Destination 4.  
print(‘Routing to [DCM.DOMAIN.COM](http://DCM.DOMAIN.COM) Destination 4’)  
SendToPeer(instanceId, ‘CentralServer\_DCM4’)  
print(‘SendToPeer - Destination 4 - done…’)  
end

if string.find(CalledAETVar, ‘\_DCM5’) ~= nil then  
– Send \_DCM5 studies to Destination 5.  
print(‘Routing to [DCM.DOMAIN.COM](http://DCM.DOMAIN.COM) Destination 5’)  
SendToPeer(instanceId, ‘CentralServer\_DCM5’)  
print(‘SendToPeer - Destination 5 - done…’)  
end

end  
print(‘DICOM Routing Complete’)  
end

On the central server, the destinations are just using this format in the Orthanc.json file:

“Destination A” : [“DESTA\_SCP”, “XXX.XXX.XXX.XXX”, 4004],  
“Destination B” : [“DESTB\_SCP”, “XXX.XXX.XXX.XXX”, 104],

I did try adding a block like this to the file, but it did not change the result previously. (Which was likely because the preferred syntax was still J2K… lol) I also wasn’t sure if this could be mixed in with the simpler version of the list, too.

“Destination B” : {  
“AET” : “DESTB\_SCP”,  
“Port” : 104,  
“Host” : “XXX.XXX.XXX.XXX”,  
“Manufacturer” : “Generic”,  
“AllowTranscoding” : true,  
}

On the central server, due to confusion trying to make sure studies for Destination A were J2K since that destination does long-term storage, but will not transcode even uncompressed studies, it was previously set to this:  
“DicomScuPreferredTransferSyntax” : “1.2.840.10008.1.2.4.90”,

I changed it to this while I was writing the first post up, and tested it before posting:

“DicomScuPreferredTransferSyntax” : “1.2.840.10008.1.2”,

It didn’t resolve the errors from Destination B… However, I missed this setting, which was likely also changed for Dest A, and likely prevents the fall-back functionality from sending the images to Dest B in an uncompressed format:

“TranscodeDicomProtocol” : false,

I’ve just changed that one to true, to see if it will at least allow the J2K studies bound for Dest B to get there in the meantime.

I do still have a second instance of Orthanc on the central server, from earlier efforts before I figured out how to route the peer-to-peer; I was hoping there was something I could do in the config or the LUA to handle it, though.

---

<div class="post-metadata">

### Author: ![Alain\_Mazy1](https://discourse.orthanc-server.org/letter_avatar_proxy/v4/letter/a/839c29/32.png) [@Alain\_Mazy1](https://discourse.orthanc-server.org/u/Alain_Mazy1)
#### Post date: [January 20, 2022, 8:32am UTC](https://discourse.orthanc-server.org/t/transcode-or-decompress-based-on-destination-dicom/2770/4 "2022-01-20T08:32:26Z")

</div>

Sorry, I’m a bit lost in your setup so only answering the question about the format of the /peers/{…}/store request.

The doc is here: [https://api.orthanc-server.com/#tag/Networking/paths/~1peers~1{id}~1store/post](https://api.orthanc-server.com/#tag/Networking/paths/~1peers~1%7Bid%7D~1store/post)

In lua, that should look like:

local query = {}  
query[“Resources”] = {}  
table.insert(query[“Resources”], instanceId)  
query[“Transcode”] = “1.2.840.10008.1.2”

local response = RestApiPost(‘/peers/DCMX/store’, DumpJson(query))

Disclaimer: not tested

HTH,

Alain

---

<div class="post-metadata">

### Author: ![Dustin\_Loftis](https://discourse.orthanc-server.org/letter_avatar_proxy/v4/letter/d/43a26b/32.png) [@Dustin\_Loftis](https://discourse.orthanc-server.org/u/Dustin_Loftis)
#### Post date: [January 20, 2022, 4:08pm UTC](https://discourse.orthanc-server.org/t/transcode-or-decompress-based-on-destination-dicom/2770/5 "2022-01-20T16:08:12Z")

</div>

Thank you! That helps a lot.

---

<div class="post-metadata">

### Author: ![Dustin\_Loftis](https://discourse.orthanc-server.org/letter_avatar_proxy/v4/letter/d/43a26b/32.png) [@Dustin\_Loftis](https://discourse.orthanc-server.org/u/Dustin_Loftis)
#### Post date: [January 20, 2022, 4:27pm UTC](https://discourse.orthanc-server.org/t/transcode-or-decompress-based-on-destination-dicom/2770/6 "2022-01-20T16:27:21Z")

</div>

As for the setup, the modality connects to the Mobile Orthanc, sending the study while calling ANYTHING\_DCM#.

The mobile Orthanc routes to the corresponding peer based on the CalledAETitle. All five peers are the same, but with five different sets of credentials set up for each mobile Orthanc device. LAPTOP##\_DCM#

The central server receives the study from the peer, and searched the username for the \_DCM#, routing based on that.

It was the only way I could find to allow the central Orthanc instance to route based only on the AE Title at the modality, when using peer-to-peer.
