nextgenhealthcare / connect

The swiss army knife of healthcare integration.
Other
870 stars 265 forks source link

[BUG] DICOM files generated by Mirth are not viewable in DICOM viewer apps #4843

Open danihodovic opened 2 years ago

danihodovic commented 2 years ago

Describe the bug

DICOM images saved by Mirth are not viewable by common DICOM viewers.

I've set up a source channel which receives DICOM images and a destination which saves them to file. The file template contains only the variable ${DICOMMESSAGE} saved in binary format. The resulting file is not viewable by common DICOM viewers, but I'm able to read DICOM metadata with pydicom.

I've tried opening in the resulting DICOM file with the following viewers without success:

I opened both the original file and the file Mirth generated in pydicom. The diff is below. I suspect that the encoding format of the pixeldata property is causing problems. I also noticed that the encoding format was changed from OW to OB in the following commit: https://github.com/nextgenhealthcare/connect/commit/16bfdc8b566497d07c2889fc72ba6b9807c5f753

https://www.diffchecker.com/3ZLxjnaP

The input file I used is "DEMO MrBrain" from the link below.

http://www.rubomedical.com/dicom_files/

jonbartels commented 2 years ago

https://forums.mirthproject.io/articles/175046-using-attachments and the "DICOM Attachment Handler Properties" section of the MC user guide from https://www.nextgen.com/-/media/files/nextgen-connect/nextgen-connect-312-user-guide.pdf are relevant here. It looks like you're getting the message attachment token written out directly instead of the attachment contents.

I am not a DICOM expert but showing your channel settings for "Use Attachments" and your file writer settings may be helpful to solving this issue.

pladesma commented 2 years ago

@danihodovic It does seem like there is a potential issue here, but like @jonbartels mentioned, it would be useful to see more of your channel settings in order to narrow down what the problem is.

danihodovic commented 2 years ago

Below is the exported channel.

<channel version="3.12.0">
  <id>cf08c378-c34a-4d27-93ee-bfb7e0941f39</id>
  <nextMetaDataId>2</nextMetaDataId>
  <name>DICOM to file</name>
  <description></description>
  <revision>5</revision>
  <sourceConnector version="3.12.0">
    <metaDataId>0</metaDataId>
    <name>sourceConnector</name>
    <properties class="com.mirth.connect.connectors.dimse.DICOMReceiverProperties" version="3.12.0">
      <pluginProperties/>
      <listenerConnectorProperties version="3.12.0">
        <host>0.0.0.0</host>
        <port>9002</port>
      </listenerConnectorProperties>
      <sourceConnectorProperties version="3.12.0">
        <responseVariable>None</responseVariable>
        <respondAfterProcessing>true</respondAfterProcessing>
        <processBatch>false</processBatch>
        <firstResponse>false</firstResponse>
        <processingThreads>1</processingThreads>
        <resourceIds class="linked-hash-map">
          <entry>
            <string>Default Resource</string>
            <string>[Default Resource]</string>
          </entry>
        </resourceIds>
        <queueBufferSize>1000</queueBufferSize>
      </sourceConnectorProperties>
      <applicationEntity></applicationEntity>
      <localHost></localHost>
      <localPort></localPort>
      <localApplicationEntity></localApplicationEntity>
      <soCloseDelay>50</soCloseDelay>
      <releaseTo>5</releaseTo>
      <requestTo>5</requestTo>
      <idleTo>60</idleTo>
      <reaper>10</reaper>
      <rspDelay>0</rspDelay>
      <pdv1>false</pdv1>
      <sndpdulen>16</sndpdulen>
      <rcvpdulen>16</rcvpdulen>
      <async>0</async>
      <bigEndian>false</bigEndian>
      <bufSize>1</bufSize>
      <defts>false</defts>
      <dest></dest>
      <nativeData>false</nativeData>
      <sorcvbuf>0</sorcvbuf>
      <sosndbuf>0</sosndbuf>
      <tcpDelay>true</tcpDelay>
      <keyPW></keyPW>
      <keyStore></keyStore>
      <keyStorePW></keyStorePW>
      <noClientAuth>true</noClientAuth>
      <nossl2>true</nossl2>
      <tls>notls</tls>
      <trustStore></trustStore>
      <trustStorePW></trustStorePW>
    </properties>
    <transformer version="3.12.0">
      <elements/>
      <inboundDataType>DICOM</inboundDataType>
      <outboundDataType>DICOM</outboundDataType>
      <inboundProperties class="com.mirth.connect.plugins.datatypes.dicom.DICOMDataTypeProperties" version="3.12.0"/>
      <outboundProperties class="com.mirth.connect.plugins.datatypes.dicom.DICOMDataTypeProperties" version="3.12.0"/>
    </transformer>
    <filter version="3.12.0">
      <elements/>
    </filter>
    <transportName>DICOM Listener</transportName>
    <mode>SOURCE</mode>
    <enabled>true</enabled>
    <waitForPrevious>true</waitForPrevious>
  </sourceConnector>
  <destinationConnectors>
    <connector version="3.12.0">
      <metaDataId>1</metaDataId>
      <name>Write file</name>
      <properties class="com.mirth.connect.connectors.file.FileDispatcherProperties" version="3.12.0">
        <pluginProperties/>
        <destinationConnectorProperties version="3.12.0">
          <queueEnabled>false</queueEnabled>
          <sendFirst>false</sendFirst>
          <retryIntervalMillis>10000</retryIntervalMillis>
          <regenerateTemplate>false</regenerateTemplate>
          <retryCount>0</retryCount>
          <rotate>false</rotate>
          <includeFilterTransformer>false</includeFilterTransformer>
          <threadCount>1</threadCount>
          <threadAssignmentVariable></threadAssignmentVariable>
          <validateResponse>false</validateResponse>
          <resourceIds class="linked-hash-map">
            <entry>
              <string>Default Resource</string>
              <string>[Default Resource]</string>
            </entry>
          </resourceIds>
          <queueBufferSize>1000</queueBufferSize>
          <reattachAttachments>true</reattachAttachments>
        </destinationConnectorProperties>
        <scheme>FILE</scheme>
        <host>/tmp/</host>
        <outputPattern>test.dcm</outputPattern>
        <anonymous>true</anonymous>
        <username>anonymous</username>
        <password>anonymous</password>
        <timeout>10000</timeout>
        <keepConnectionOpen>true</keepConnectionOpen>
        <maxIdleTime>0</maxIdleTime>
        <secure>true</secure>
        <passive>true</passive>
        <validateConnection>true</validateConnection>
        <outputAppend>false</outputAppend>
        <errorOnExists>false</errorOnExists>
        <temporary>true</temporary>
        <binary>true</binary>
        <charsetEncoding>DEFAULT_ENCODING</charsetEncoding>
        <template>${DICOMMESSAGE}</template>
      </properties>
      <transformer version="3.12.0">
        <elements/>
        <inboundDataType>DICOM</inboundDataType>
        <outboundDataType>DICOM</outboundDataType>
        <inboundProperties class="com.mirth.connect.plugins.datatypes.dicom.DICOMDataTypeProperties" version="3.12.0"/>
        <outboundProperties class="com.mirth.connect.plugins.datatypes.dicom.DICOMDataTypeProperties" version="3.12.0"/>
      </transformer>
      <responseTransformer version="3.12.0">
        <elements/>
        <inboundDataType>DICOM</inboundDataType>
        <outboundDataType>DICOM</outboundDataType>
        <inboundProperties class="com.mirth.connect.plugins.datatypes.dicom.DICOMDataTypeProperties" version="3.12.0"/>
        <outboundProperties class="com.mirth.connect.plugins.datatypes.dicom.DICOMDataTypeProperties" version="3.12.0"/>
      </responseTransformer>
      <filter version="3.12.0">
        <elements/>
      </filter>
      <transportName>File Writer</transportName>
      <mode>DESTINATION</mode>
      <enabled>true</enabled>
      <waitForPrevious>true</waitForPrevious>
    </connector>
  </destinationConnectors>
  <preprocessingScript>// Modify the message variable below to pre process data
return message;</preprocessingScript>
  <postprocessingScript>// This script executes once after a message has been processed
// Responses returned from here will be stored as &quot;Postprocessor&quot; in the response map
return;</postprocessingScript>
  <deployScript>// This script executes once when the channel is deployed
// You only have access to the globalMap and globalChannelMap here to persist data
return;</deployScript>
  <undeployScript>// This script executes once when the channel is undeployed
// You only have access to the globalMap and globalChannelMap here to persist data
return;</undeployScript>
  <properties version="3.12.0">
    <clearGlobalChannelMap>true</clearGlobalChannelMap>
    <messageStorageMode>DEVELOPMENT</messageStorageMode>
    <encryptData>false</encryptData>
    <removeContentOnCompletion>false</removeContentOnCompletion>
    <removeOnlyFilteredOnCompletion>false</removeOnlyFilteredOnCompletion>
    <removeAttachmentsOnCompletion>false</removeAttachmentsOnCompletion>
    <initialState>STARTED</initialState>
    <storeAttachments>true</storeAttachments>
    <metaDataColumns>
      <metaDataColumn>
        <name>SOURCE</name>
        <type>STRING</type>
        <mappingName>mirth_source</mappingName>
      </metaDataColumn>
      <metaDataColumn>
        <name>TYPE</name>
        <type>STRING</type>
        <mappingName>mirth_type</mappingName>
      </metaDataColumn>
    </metaDataColumns>
    <attachmentProperties version="3.12.0">
      <className>com.mirth.connect.server.attachments.dicom.DICOMAttachmentHandlerProvider</className>
      <type>DICOM</type>
      <properties/>
    </attachmentProperties>
    <resourceIds class="linked-hash-map">
      <entry>
        <string>Default Resource</string>
        <string>[Default Resource]</string>
      </entry>
    </resourceIds>
  </properties>
  <exportData>
    <metadata>
      <enabled>true</enabled>
      <lastModified>
        <time>1636567679690</time>
        <timezone>Europe/Stockholm</timezone>
      </lastModified>
      <pruningSettings>
        <archiveEnabled>true</archiveEnabled>
        <pruneErroredMessages>false</pruneErroredMessages>
      </pruningSettings>
    </metadata>
  </exportData>
</channel>