Lua Script to get Institution name and move it to folder

Hi all,

I am studying up on Lua Scripting and I am trying to find out if it is possible for a Lua Script to open a Dicom file, extract the metadata tag “InstitutionName” and then move that file into a folder with that same name? So and example would be:

  1. Open filename
  2. get InstituionName
  3. Assign that name into a variable
  4. Close the file
  5. Move filename into “C:\database\(Contents of variable used to store InstituionName)”
  6. End

This in effect would empty the main database of Orthanc and create a new user friendly directory with the Clinic names.

Is there such a script now? If not, are there native commands in Orthanc that I can use in conjunction with Lua script to accomplish this?

Any links and advise is appreciated.

Thank you.

Craig.

Hi Craig,

I’ve just added such a sample lua script here: https://bitbucket.org/osimis/orthanc-setup-samples/src/master/lua-samples/save-to-custom-tree.lua

function sanitize(s)
– remove all characters that you don’t want to have in a path
s = string.gsub(s, " ", “-”)
s = string.gsub(s, “/”, “-”)
s = string.gsub(s, “\”, “-”)

return s
end

function OnStoredInstance(instanceId, tags, metadata, origin)
– store files in a more human friendly hierarchy and then, delete the instance from Orthanc

local institutionName = sanitize(tags[“InstitutionName”])
local patientId = sanitize(tags[“PatientID”])
local studyId = tags[“StudyInstanceUID”]
local seriesId = tags[“SeriesInstanceUID”]
local sopInstanceId = tags[“SOPInstanceUID”]

if (institutionName == nil or institutionName == “”) then
print(“no InstitutionName, don’t know what to do”)
else
local dicom = RestApiGet(‘/instances/’ … instanceId … ‘/file’)
local folder = “/tmp/dicom-files/” … institutionName … “/” … patientId … “/” … studyId … “/” … seriesId
os.execute("mkdir -p " … folder)
local path = folder … “/” … sopInstanceId … “.dcm”
local file = io.open(path, “w”)
io.output(file)
io.write(dicom)
io.close(file)

Delete(instanceId)
end
end

Hope this helps,

Alain

All,

Background on me: Started this project 9 days. I have a very good understanding of how scripting and pacs software work and after much reading, a basic understanding of Lua. I actually install digital equipment as a profession and work with many pacs systems. Just wanted to provide that info for reference so people have an idea of where I am at as far as experience…

Its been a while since I had to troubleshoot and I totally forgot about the logs. So, went to the logs and did confirm that this script is definitely attempting to run (which nullifies all posts/emails before this one) . . . but I get these errors:

E0411 21:29:24.422025 OrthancException.cpp:58] Cannot execute a Lua command: [string “line”]:30: bad argument #1 to ‘close’ (FILE* expected, got nil)
E0411 21:29:24.422025 LuaScripting.cpp:810] Error while processing Lua events: Cannot execute a Lua command
E0411 21:29:32.776855 OrthancException.cpp:58] Cannot execute a Lua command: [string “line”]:30: bad argument #1 to ‘close’ (FILE* expected, got nil)
E0411 21:29:32.776855 LuaScripting.cpp:810] Error while processing Lua events: Cannot execute a Lua command

These errors are from the example provided. Another mistake I made is that I “assumed” (which I hate when I do that) that it would run as is and did not consider that there might be some adjustments that need to happen. After all the reading I have done, the script makes sense to me and from the info provided from the logs, “FILE” as I understand it, is the variable to which a filename is supposed to entered into and Orthanc is reporting that it is null. Line 30 is this in the script: io.close(file) - “30: bad argument #1 to ‘close’ (FILE* expected, got nil)”

I am on a Windows 10 pro installation.

So my questions are:

  1. Did I interpret the logs correctly or at least am I on the right track?
  2. Are there more parameters that I need to add to the script to adapt it to my own installation?
  3. What additional information do I need to provide if I missed any?
  4. Can someone provide an example of how the end result looks like? I have a good idea, but just wouldn’t mind a confirmation so I know what to expect.

Things I did to try to resolve issue: (this was before I thought of looking at the logs)

  1. Gave full permissions to the destination folder. Assumed it was the folder that is defined in the config, which for me is C:\Orthanc.
  2. More reading. Specifically on the error codes and what might cause this.
  3. Asked questions.

Thank you all for your contributions and advice. It is very much appreciated.

Respectfully,

Craig Rollison.

Hi Craig,

I’ve just adapted the script for Windows paths: https://bitbucket.org/osimis/orthanc-setup-samples/commits/a7c4ce0dc4e91cacaec170dddc4ad19c7caf17bf

Works fine on my machine, I did not had to care about permissions of the destination folder.

HTH

Alain.

function sanitize(s)
if s == nil then
return nil
end
– remove all characters that you don’t want to have in a path
s = string.gsub(s, " ", “-”)
s = string.gsub(s, “/”, “-”)
s = string.gsub(s, “\”, “-”)

return s
end

– adapt for windows/linux
– don’t forget trailing / or \

– root = ‘/tmp/dicom-files/’
– sep = ‘/’

root = ‘C:\Orthanc-organized-storage\’
sep = ‘\’

function OnStoredInstance(instanceId, tags, metadata, origin)
– store files in a more human friendly hierarchy and then, delete the instance from Orthanc

local institutionName = sanitize(tags[“InstitutionName”])
local patientId = sanitize(tags[“PatientID”])
local studyId = tags[“StudyInstanceUID”]
local seriesId = tags[“SeriesInstanceUID”]
local sopInstanceId = tags[“SOPInstanceUID”]

if (institutionName == nil or institutionName == “”) then
print(“no InstitutionName, don’t know what to do”)
else
local dicom = RestApiGet(‘/instances/’ … instanceId … ‘/file’)
local folder = root … institutionName … sep … patientId … sep … studyId … sep … seriesId
print(folder)

os.execute("mkdir -p " … folder)
local path = folder … sep … sopInstanceId … “.dcm”
local file = io.open(path, “w”)
io.output(file)
io.write(dicom)
io.close(file)

Delete(instanceId)
end
end

Alain,

YOU ARE AWESOME! Thank you very much. It works. At first, I thought you had just added some code to the original and of course, when I just added the code that I thought was an edit, it did not work. Then after I thought about it, I took a second look at the adapted script you posted and noticed there were more changes than I had originally noticed. So, then the whole copy and paste thing happen and a test later, WAH-LAH! I did learn a lot from this and appreciate your help very much. To be honest, it was pretty fun looking at the original script and trying to figure out why it was having an issue. I stared at that for most of the day today, trying to figure out how the variable “root” fit into the script (because I did not copy that originally) then I saw it in the latest and it started to make sense.

Additional questions. Where can I donate? Do you have that link you recommendation of someone that I can employ/pay to assist me in another endeavor? (You sent one but I am unable to locate the link you sent)

Grateful and Respectfully,

Craig Rollison

Alain,

Script you posted works, but for some reason I am unable to open the dicom in a viewer from the new folder. Did this happen to you? I commented out the “Delete(instanceId)” in the script so that I could have a copy in Orthanc folder and I can open those. I am looking into it. I do not see why this would happen aside from the fact that when the dicom goes into the default folder, it does not have the “.DCM” extension. The script is pretty cut and dry and to the point. I do not see any “conversions” or “alterations” that could affect the file itself other than adding the “.dcm” extension to it, which shouldn’t affect the file like that.

Please give me about 3 days on this as I would like to do the research and see if I can find the answer. This is interesting stuff and I want to see if I can figure it out. You have been so helpful and I am not afraid of work to get the desired results. I still want to donate please.

Thank you.

Craig Rollison

Alain,

Got it. So the line - “local file = io.open(path, “w”)” needed a ‘b’ to look like this: local file = io.open(path, “wb”). Script works wonderfully. I can open dicoms from the new location. According to http://www.w3big.com/lua/lua-file-io.html, the ‘b’ in the mode section treats the file as binary (for those who didn’t know such as myself) and to be honest, this was not something I spotted and said, “Oh there needs to be this here”, I just added it and tried it. I did not know what it was until after it worked. In short, I got lucky.

Again, thank you for everything.

Craig.

Hi,

Shame on me for not testing the script completely and thanks for notifying the bug !

Concerning the links:

Best regards,

Alain.

Alain,

“For those who see mistakes, others see opportunity.” I, for one, am happy that you didn’t! If that had not happen, I might not have done the research and got the chance to learn. Your human like the rest of us and with your willingness to share information renews my faith in humanity. Very much appreciated for all your help.

Thank you again for the links.

Respectfully,

Craig Rollison