Tag Archives: Store SCU

Automating DICOM Printer 2

This article is intended for IT staff. It includes samples of XML files that might be difficult to understand for the non-initiated. If you would like to learn about automated DICOM storage without the technical jargon, please send us an email.

One of the consequences of implementing a PACS, is that everything has to be sent there.  This has produced a world of patchwork solutions that often involve generating paper records for the sole purpose of digitizing them back into electronic form.

I truly can’t think of a greater offense to the purpose of electronic health records than to make them complicit in the needless use of paper.  Not to mention the tragedy of entire human working lives spent scanning things that have just come out of a printer.

Attaching Paper to PACS

DICOM Printer 2 was originally designed to address this problem.  The XML-based configuration, regular expression matching, plug-in interfaces and capability to operate according to data-driven logic gives it a natural ability to fit into whatever part of patient workflows are most wasteful of human time.

In this post, I go through a short example of a common configuration, broadly applicable to the following workflow:

  1. A document is generated; perhaps by a fax server, a medical instrument (such as BMD), or a staff member who transcribes a dictated report.
  2. The document is printed to paper.
  3. The document is prepared into a scanning batch, and scanned.
  4. Office staff open the scanned document and manually upload, link, or otherwise select a patient record to which it should be attached.
  5. The document arrives in PACS for permanent storage.

Any reasonable person can see that steps 2 and 3 are unnecessary, and step 4 often involves visual data searching that can quite often be automatically performed by a computer.

One of our most common configurations, results in the following workflow:

  1. A document is generated.
  2. DP2 automatically reads patient and study information from the contents.
  3. DP2 queries PACS and/or Worklist for the patient record, associates it, and,
  4. The document arrives in PACS.

No paper, no shameless waste of human life, still the same result in PACS.  Here is the configuration that is needed to achieve this:

<DicomPrinterConfig>
  ...
  <ActionsList>
    <ParseJobTextFile name="ParseContents">
      <DcmTag tag="(8,50)">^(.*)\-.*$</DcmTag>
      <DcmTag tag="(8,60)">^.*\-(.*)$</DcmTag>
    </ParseJobFileName>
    <Query name="Query" type="Worklist">
      <DcmTag tag="(0008,0050)" />
      <DcmTag tag="(0008,0060)" />
      <DcmTag tag="(0010,0020)" />
      <DcmTag tag="(0020,000D)" />
      <ConnectionParameters>
        <MyAeTitle>DICOMPRINTER2</MyAeTitle>
        <PeerAeTitle>DVT</PeerAeTitle>
        <Host>localhost</Host>
        <Port>104</Port>
      </ConnectionParameters>
    </Query>
    <Store name="Store">
      <Compression type="RLE" />
      <ConnectionParameters>
        <PeerAeTitle>CONQUESTSRV1</PeerAeTitle>
        <Host>192.168.0.41</Host>
        <Port>5678</Port>
      </ConnectionParameters>
    </Store>
  </ActionsList>
  <Workflow>
    <Perform action="ParseContents" onError="Hold" />
    <Perform action="Query" onError="Suspend" />
    <If field="QUERY_FOUND" value="1">
      <Statements>
        <Perform action="Store" />
      </Statements>
      <Else>
        <Suspend resumeAction="Query" />
      </Else>
    </If>
  </Workflow>
</DicomPrinterConfig>

The parts of this file seem complex, but it is really comprised of only a few action definitions and a workflow that implements them.

The first action parses the contents of the printed document, looking for accession and modality values:

    <ParseJobTextFile name="ParseContents">
      <DcmTag tag="(8,50)">Accession: (.*)$</DcmTag>
      <DcmTag tag="(8,60)">Modality: (.*)$</DcmTag>
    </ParseJobFileName>

The two DcmTag elements describe regular expressions used to extract the values, and the tag attributes define where the data is to reside. The next action is:

<Query name="Query" type="Worklist">
      <DcmTag tag="(0008,0050)" />
      <DcmTag tag="(0008,0060)" />
      <DcmTag tag="(0010,0020)" />
      <DcmTag tag="(0020,000D)" />
      <ConnectionParameters>
        <MyAeTitle>DICOMPRINTER2</MyAeTitle>
        <PeerAeTitle>DVT</PeerAeTitle>
        <Host>localhost</Host>
        <Port>104</Port>
      </ConnectionParameters>
    </Query>

Pretty self-explanatory: query worklist with accession and Modality, and retrieve Patient ID and Study UID. Note that if DICOM header attributes have previously been set in the workflow, then including them in a query automatically makes them part of the query parameters. In this case, because Accession and Modality will have already been extracted from the document, then the query would be based on these two parameters, and retrieve two more. The ConnectionParameters group is self-explanatory.

The next action stores the document to PACS:

    <Store name="Store">
      <Compression type="RLE" />
      <ConnectionParameters>
        <PeerAeTitle>CONQUESTSRV1</PeerAeTitle>
        <Host>192.168.0.41</Host>
        <Port>5678</Port>
      </ConnectionParameters>
    </Store>

Once these actions have been defined, the magic can be performed. The following piece of the configuration file defines how these actions will be composed into an automated workflow:

  <Workflow>
    <Perform action="ParseContents" onError="Hold" />    #1
    <Perform action="Query" onError="Suspend" />         #2
    <If field="QUERY_FOUND" value="1">                   #3
      <Statements>
        <Perform action="Store" />                       #4
      </Statements>
      <Else>
        <Suspend resumeAction="Query" />                 #5
      </Else>
    </If>
  </Workflow>

The process is straightforward in this case:

  1. Extract document contents, according to previously defined ParseContents action, if nothing is found, stop processing and hold the document in queue indefinitely.
  2. Query worklist using retrieved values, if the query fails, suspend the job for a pre-determined amount of time, and then retry.
  3. If query completes successfully, and a record is found then,
  4. Store to PACS.
  5. If the query returns no records, suspend and retry the query later.

The last step helps if the timing of data in worklist (or PACS) does not precede document generation.  A situation like this often arises when requisitions, which are the first documents to arrive, need to be attached to studies after they have been performed.

There are actually a multitude of variants of this workflow, sometimes involving more than one query, sometimes requiring a little bit of user input to augment the record, but the general process is a very common application of DICOM Printer 2.

We hope you too can save a few forests’ worth of trees and an FTE or two, by implementing DICOM Printer 2 in your practise.

DICOM Multi-tool by Example

Introduction

DICOM Multi-tool (“DMT”) is a multi-purposed DICOM engine. It was originally written to provide functionality for specific medical devices, but has been authored in such a way that it can be used in a variety of contexts, including Query, Store, Move, Print and Worklist in both SCU and SCP roles.

The following sections are extracted from the DMT manual, with the aim to provide a concise and relevant peek at the fundamental usage paradigm. Our purpose here is to provide an instantly usable example, which is why this document contains a little more by way of actual links, and specific procedures, which do not normally form part of our documentation.

Getting DMT

Downloading DMT for Testing Purposes

A working copy of the DICOM Multi-tool is available via the following link:

DICOM Multi-tool Development Package v0.5.1.105

This package includes the binaries, as well as a set of selected example queries. After installation, please explore the Start Menu for new links.

Note: Build 91 of DMT, which has been selected for this example, is out of date. Although contemporary request syntax has changed somewhat from this version, it is still more then adequate for this purpose.

Installation

Two modes of installation are available, generic and silent, which can be selected using a command-line argument.

Silent Mode Installation

In silent mode no window is shown and every parameter is either set to its default value, or overriden with additional comman-line arguments. Thus far, three arguments have been exposed — program files location, whether to install as a service, as well as where to store the configuraton file.

Generic Mode Installation

Generic mode of installation is the default. It allows the user to select a program files location path and whether or not to install the DICOM Multi-tool service.

This mode of installation will occur when you double-click the installation package. Please do so now and follow on-screen instructions. You may be asked to reboot your computer after installation has completed.

Usage

Basic Principles

DICOM Multi-tool listens for incoming requests on one of selected communication channels. Requests are text-based — they have a very similar format to HTTP requests — and allow the caller to engage and monitor a single DICOM service, retrieve application status, check log entries and, if necessary, terminate the application.

Requests to start a DICOM service always require a number of parameters. They take the form of an XML document, each one specific to a given task.

The following is an example of a request to start a client that stores all .dcm files in a specified folder to a PACS running at 127.0.0.1 and port 104 using the RLE Lossless format (other formats include JPEG, RAW, etc):

<?xml version="1.0" encoding="UTF-8"?>
<Request version="0.0.1">
  <Command>START StorageScu</Command>
  <Arguments><![CDATA[<?xml version="1.0" encoding="utf-8"?>
  <StorageScuParameters>
    <ConnectionParameters>
      <MyAeTitle>DMT</MyAeTitle>
      <PeerAeTitle>PACS</PeerAeTitle>
      <HostAddress>127.0.0.1</HostAddress>
      <Port>104</Port>
    </ConnectionParameters>

    <DataSource type="FileSystem">
      <Parameter>
        <Name>NameFilters</Name>
        <Value>DCM:*.dcm|*.dicom</Value>
      </Parameter>
      <Parameter>
        <Name>Path</Name>
        <Value>C:\Users\Public\Documents\</Value>
      </Parameter>
    </DataSource>

    <TransferSyntax>RLE Lossless</TransferSyntax>
  </StorageScuParameters>]]></Arguments>
  <ExpirationTime>2012-10-10T10:10:10</ExpirationTime>
  <Uuid>67C8770B-44F1-410A-AB9A-F9B500020001</Uuid>
</Request>

Once a request is read, DICOM Multi-tool attempts to parse it and invoke the specified function or task. Results are passed back to the caller using similar, HTTP request-based, responses.

Responses indicate status of the operation and can provide intermediate results for some of the tasks. For example, when a DICOM query client is used, every response contains a single matching record. Such pieces of data are also embedded in XML documents.

The format of both requests and responses is covered in detail in the DMT Manual.

Start-up Modes

DICOM Multi-tool can be used in two modes: as a standalone console application, or as a Windows service. The following table shows the differences. They are covered further.

Standalone Service
Can be executed using a path stored in the registry Starts automatically with Windows. Can also be executed or terminated using the native Windows service controller or by invoking the application with specific command-line arguments
Supports both communication channels (network and console) Supports only network communciation
Settings can be provided only using command-line arguments Loads settings from the configuration file
Sends log messages to the console and stores them internally Log messages are only stored internally and are available on request

Standalone Start-up Mode

In standalone mode DICOM Multi-tool starts as a typical Windows console application. The software setup program creates a link to it in the Start Menu, allowing easy execution. You can also do this manually using a command-line interpreter (cmd.exe). Just change the directory to where the DICOM Multi-tool has been installed and start it, passing the -e parameter, e.g.

$ cd "C:\Program Files\Flux Inc\DICOM Multi-tool"
$ "DICOM Multi-tool.exe" -e

Note: When showing outut of Windows command-line interpreter, for the sake of readability we remove current directory path and replace command-prompt with UNIX-style $ mark.

In order that you may access it from within your application, the setup program stores the full path to the DICOM Multi-tool executable in the Windows registry. This value is stored in the following key: HKEY_LOCAL_MACHINE\SOFTWARE\Flux Inc.\DICOM Multi-tool under the Program Path name and is of type REG_SZ.

By default in standalone mode DICOM Multi-tool accepts requests and provides responses using the console. You can change this behaviour by providing a -communication-channel NETWORK argument right after the -e switch.

Hint: A full listing of command-line arguments and registry settings is provided in Appendices A and B at the end of the DMT Manual.

Standalone mode is used mainly for testing purposes but can also be invoked in a production environemnt; for example, when access to system services is constrained.

Service Start-up Mode

Unless selected otherwise, the DICOM Multi-tool installation program creates a new system service in Windows, called “DICOM Multi-tool” and configures it to start automatically with the operating system. You can query the current state of this service by executing the DICOM Multi-tool program with a -v switch, like so:

$ cd "C:\Program Files\Flux Inc\DICOM Multi-tool"
$ "DICOM Multi-tool.exe" -v
The service
    DICOM Multi-tool
    DICOM Multi-tool.exe

is installed and not running

In order to start the service, you can either invoke the executable without any parameters, or use system tools availble in windows, e.g.:

$ net start "DICOM Multi-tool"
The DICOM Multi-tool service is starting.
The DICOM Multi-tool service was started successfully.

With DMT service you can communiate only using network connection.

Communication

Messages

As mentioned in the introductionary part above, communication between DICOM Multi-tool and users is conveyed using text-based, HTTP-like, messages:

  • requests are created by a user and sent to the Multi-tool,
  • responses are sent back by the application.
Structure Overview

There are two main sections contained within both request and response messages.

Each message contains a header comprised of plain text and encoded using strict rules.
The first element of every header contains a message-specific string followed by a line feed character. For requests this string specifies a command to be executed, e.g. QUIT. For responses, it indicates a status like ERROR 3.

Following the first, special, line are header fields. Header fields are colon-separated name-value pairs, also in a plain text string format and terminated by a line feed character. The last header field must be terminated by two line feed characters, indicating the end of the entire header.

The following is an example of a request header, with line feed characters indicated by <LF> marks:

START QueryScu<LF>
Version: 0.1<LF>
Date: 2013-03-01T09:57:11<LF>
Body-Length: 475<LF>
Body-Type: text/xml<LF>
<LF>

Similarily, a response header may look like this:

ACK<LF>
Version: 0.1<LF>
Request-Id: 31<LF>
<LF>

Immediately following the header is the message body. This portion is optional and can contain virtually any information. Currently, however, the message body supports storage of only a single XML document with command arguments (in case of requests) or operation results (in case of responses). For example, the following are DICOM query client arguments stored in the body of a request message:

<?xml version="1.0" encoding="UTF-8"?>
<QueryScuParameters>
  <ConnectionParameters>
    <MyAeTitle>DMT_AE</MyAeTitle>
    <PeerAeTitle>PACS</PeerAeTitle>
    <HostAddress>10.10.16.2</HostAddress>
    <Port>104</Port>
  </ConnectionParameters>
  <Type>PATIENT</Type>
  <Level>PATIENT</Level>
  <Identifier>
    <Dataset>
      <Tag group="0010" element="0010">WF1239</Tag>
      <Tag group="0010" element="0020"></Tag>
    </Dataset>
  </Identifier>
</QueryScuParameters>

Hint: Message syntax is described using EBNF notation in the DMT Manual.

Requests

The first line of every request message must specify a command to be executed by the Multi-tool. The most common command is the START command, which tells DMT to start a DICOM service or some other task. Immediately following the START string there must be a space character and then a service or task name.

Subsequent lines

  • Version, mandatory, tells the applicaton what is the version of this request,
  • Date, optional, the date and time of when this request was sent,
  • Expires-After, optional, default 30, specifies number of seconds Multi-tool has to process this message (Note: to process, not to perform the task!). When no Date is provided, the timer starts when the first line of the request is received.
  • Body-Type, mandatory when body is present, specifies body format using Internet media type identifier (see. RFC 2046). Only the text/xml and application/xml formats are supported at the moment,
  • Body-Length, specifies number of bytes (octets) comprsing the body. Required when Body-Format indicates a format inappropriate for streaming.

Hint: Since prsently only XML documents can be stored in the message body this field is optional, allowing clients to write XML directly to pipe or socket and not witholding it in order to calculate the length.

Responses

Since complete integration is not an aim of this document, this section has been omitted. Response format is defined in detail in the DICOM Multi-tool Manual.

Learning by Example

Now we’re ready to proceed to a concrete example. First we walk through installing some supporting tools, and then proceed directly to authoring a simple request, and receiving a response.

Preparing Some Tools

A large portion of the testing of any DICOM application can be performed using one or more of the tools provided as part of the Offis DCMTk toolkit. This toolkit contains binaries for storage, echo, and query, as well as those for about two dozen additional contexts.

For example, using DCMTk you can run a simple PACS (storescp.exe), which stores to a local folder, and responds to queries (findscp.exe). You can also echo this PACS using echoscu.exe and run queries using findscu.exe.

We will only use one of the DCMTk binaries, storescp.exe, for this example, but obtaining the entire kit will assist you greatly with any future DICOM development.

Installing DCMTk binaries on Windows

To install DCMTk binaries for Windows:

  1. Download the appropriate package from:

    http://dicom.offis.de/dcmtk.php.en#bin

    At time of writing, there is only a 32-bit Windows package, downloadable from this location.

  2. Unzip the package into a dedicated folder, e.g., c:\dcmtk\
  3. Add this folder to your system path as you will likely be using these tools often.

Confirming Installation of DCMTk

To confirm that you can run DCMTk from your shell, try a command like:

$ echoscu --version

Which should ouput something like the following, which was produced on a Windows 7, using the 32-bit binary package:

$dcmtk: echoscu v3.6.0 2011-01-06 $
echoscu: DICOM verification (C-ECHO) SCU
Host type: x86-Windows
External libraries used:
- ZLIB, Version 1.2.5

Using DCMTk as a Store SCP

Included within the DCMTk archive appropriate for your platform, is storescp (storcescp.exe on Windows), which can be used to run a simple SCP that responds to C-ECHO requests and stores files in a local folder.

To create a simple Store SCP, simply drop into a command shell, navigate to the DCMTk binary folder, and run:

$ storescp.exe -v 10104

This creates an instant daemon that stores all received DICOM datasets into sub-folders of the current path. The SCP will accept storage requests on port 10104 from any AE title, and does not require any particular destination AE title be specified.

Port 10104 has been chosen because creating listeners on ports lower than 1024 sometimes requires administrative priveleges.

To quit the store SCP daemon, press ctrl-c.

Example: DICOM Multi-tool Echo SCU

In this example, we will be creating a simple Store SCP using DCMTk and performing a C-ECHO request using DICOM Multi-tool. The purpose of this example is to familiarise the reader with one of the available invocation and communication interfaces.

Onward

First, add DICOM Multi-tool to your path:

  1. Open up the Advanced System Properties of your Windows installation, and add the following to your PATH:
    %PATH%;C:\\Program Files\\Flux Inc\\DICOM Multi-tool
    
  2. Start a command shell and run:
    $ DicomMultiTool.exe
    
  3. The command should execute, and wait for command input. This will produce no output, but the tool will continue to accept characters you type until you press ctrl-c, which you should do now.

Create a Store SCP

Next, create a simple Store SCP, using DCMTk’s storescp utility — this is essentially a mini-PACS. If you haven’t yet installed DCMTk, then please follow the instructions located earlier in this document.

To create a simple Store SCP using DCMTk, run:

$ storescp -v -d 10104
D: $dcmtk: storescp v3.6.0 2011-01-06 $
D:

The -d and -v arguments cause storescp to output the verbose information above. This process will continue to listen for connections on port 10104 until you press ctrl-c.

Create the C-ECHO Request

Now we create a Verification SCU request XML document, and invoke DMT for the actual request.

  1. Open a command shell, and make a copy of the Echo SCU example to the %TEMP% folder:
    $ cd %TEMP%
    $ copy "C:\Program Files\Flux Inc\DICOM Multi-tool\Examples\Verification SCU\01.xml" .\
        1 file(s) copied.
    
  2. Open this duplicate XML document using your favorite XML editor — we like this one, but you can use notepad if you wish:
    $ notepad %TEMP%\01.xml
    
  3. Make the following changes to the XML:
    a. Change HostAddress to 127.0.0.1
    b. Change port to 10104
    c. The ExpirationTime is deliberately set into the future, so you can leave it as is.

    The finished request file will look something like:

    <?xml version="1.0" encoding="utf-8"?>
    <Request version="0.0.1">
      <Command>START VerificationScu</Command>
      <Arguments><![CDATA[<?xml version="1.0" encoding="utf-8"?>
      <VerificationScuParameters>
        <ConnectionParameters>
          <MyAeTitle>DMT</MyAeTitle>
          <PeerAeTitle>DCMTK</PeerAeTitle>
          <HostAddress>127.0.0.1</HostAddress>
          <Port>10104</Port>
          <Timeout>1</Timeout>
        </ConnectionParameters>
      </VerificationScuParameters>]]></Arguments>
      <ExpirationTime>2013-10-10T10:10:10</ExpirationTime>
      <Uuid>67C8770B-44F1-410A-AB9A-F9B500020001</Uuid>
    </Request>
    

    Note: A perceptive reader will notice that the syntax of this requests is a little different than the one provided earlier in this document. That is because build 91 is older, and we’ve made the syntax a smidgen more readable since then. The key difference in newer versions is that the request body no longer needs to be enclosed in a CDATA block.

  • Save the XML, this is now our complete request.
  • Invoke DMT and Pass the Request

    That’s it, we’re ready to run DMT, to do this:

    1. Make sure the Store SCP is still running in an open command window.
    2. Open a new shell or find one that’s available.
    3. Pass the request to a new instance of DICOM Multi-tool:
      type %TEMP%\01.xml | DicomMultiTool.exe
      

      Note: The format of this command is necessary because DMT accepts requests using STDIN, and passes results using STDOUT. Non-console modes of operation, such as using TCP requests, would obviously not involve this syntax.

    Result

    Assuming all goes well, the command above will produce the following output:

    <?xml version="1.0"?>
    <Response version="0.0.1">
      <Status>ACK</Status>
      <Data><![CDATA[<?xml version="1.0"?>
        <CommunicationChannelProperties version="0.0.1">
          <Type>CONSOLE</Type>
          <Properties count="0"/>
        </CommunicationChannelProperties>
      ]]></Data>
      <Message>ACK</Message>
      <RequestUuid>{67c8770b-44f1-410a-ab9a-f9b500020001}</RequestUuid>
    </Response>
    <?xml version="1.0"?>
    <Response version="0.0.1">
      <Status>FINISHED</Status>
      <Data><![CDATA[<?xml version="1.0"?>
      <VerificationScuResult>
        <Status>SUCCESS</Status>
      </VerificationScuResult>
      ]]></Data>
      <RequestUuid>{67c8770b-44f1-410a-ab9a-f9b500020001}</RequestUuid>
    </Response>
    

    Success! Our Echo request is complete. A quick look at the DCMTk command window will reveal the association log and more detailed information, which is not particularly relevent for actual use, but can be informative when troubleshooting.

    Conclusion

    We hope this example has served to illustrate basic DICOM Multi-tool use. If you wish to learn more, then please contact us immediatley. We love to drone on and on about the most obscure aspects of our code and we look forward to hearing from you so that we may bore you nearly to death.


    Supplement

    Installing DCMTk binaries on OS X

    To obtain DCMTk for Mac, make sure you have the latest version of Xcode installed, as well as Homebrew, and then run:

    brew install dcmtk
    

    Or, if you prefer MacPorts, the equivalent command is:

    sudo port install dcmtk
    

    Once you’ve done this, the binaries are available for use in any directory.

    Installing DCMTk binaries on Ubuntu

    To install on any Debian-based OS that supports Aptitude, run:

    sudo apt-get install dcmtk
    

    This automatically installs the libraries and permits use from any path.

    Note that if you will be testing DMT from a Windows machine against services running on a posix box, then you will likely have to adjust the IP addresses in examples to reflect this structural dichotomy.