瀏覽代碼

Add ctkDcmSCU class using code from pre-release DCMTK

The enhanced DcmSCU class has support for C-GET calls
which won't be in a release version of DCMTK for a year
or so. In the near term we use this copy of the class
with the idea that we can replace is later with the
real class from dcmtk.
Steve Pieper 13 年之前
父節點
當前提交
251d07a5c1

+ 2 - 2
Applications/ctkDICOMDemoSCU/ctkDICOMDemoSCUMain.cpp

@@ -19,7 +19,7 @@
 =========================================================================*/
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
-#include "dcmtk/dcmnet/scu.h"
+#include "ctkDcmSCU.h"
 
 // STD includes
 #include <cstdlib>
@@ -53,7 +53,7 @@ int main(int argc, char** argv)
   }
     
   // Setup SCU
-  DcmSCU scu;
+  ctkDcmSCU scu;
   scu.setPeerHostName(host);
   scu.setPeerPort(port);
   OFString verificationSOP = UID_VerificationSOPClass;

+ 5 - 0
Libs/DICOM/Core/CMakeLists.txt

@@ -29,6 +29,11 @@ set(KIT_SRCS
   ctkDICOMRetrieve.h
   ctkDICOMTester.cpp
   ctkDICOMTester.h
+  # enhanced DcmSCU class - to be removed when
+  # corresponding functionality is in a 
+  # DCMKT release - see notes in header file.
+  ctkDcmSCU.cc
+
 )
 
 # Abstract class should not be wrapped !

+ 11 - 11
Libs/DICOM/Core/ctkDICOMQuery.cpp

@@ -47,7 +47,10 @@
 #include <dcmtk/ofstd/ofstd.h>        /* for class OFStandard */
 #include <dcmtk/dcmdata/dcddirif.h>   /* for class DicomDirInterface */
 
-#include <dcmtk/dcmnet/scu.h>
+// NOTE: using ctk stand-in class for now - switch back
+// to dcmtk's scu.h when cget support is in a release version
+//#include <dcmtk/dcmnet/scu.h>
+#include <ctkDcmSCU.h>
 
 static ctkLogger logger ( "org.commontk.dicom.DICOMQuery" );
 
@@ -66,7 +69,7 @@ public:
   QString                 Host;
   int                     Port;
   QMap<QString,QVariant>  Filters;
-  DcmSCU                  SCU;
+  ctkDcmSCU               SCU;
   DcmDataset*             Query;
   QStringList             StudyInstanceUIDList;
 };
@@ -324,7 +327,7 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
     }
   emit progress(30);
 
-  FINDResponses *responses = new FINDResponses();
+  OFList<QRResponse *> responses;
 
   Uint16 presentationContext = 0;
   // Check for any accepted presentation context for FIND in study root (dont care about transfer syntax)
@@ -341,21 +344,20 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
     }
   emit progress(40);
 
-  OFCondition status = d->SCU.sendFINDRequest ( presentationContext, d->Query, responses );
+  OFCondition status = d->SCU.sendFINDRequest ( presentationContext, d->Query, &responses );
   if ( !status.good() )
     {
     logger.error ( "Find failed" );
     emit progress("Find failed");
     d->SCU.closeAssociation ( DCMSCU_RELEASE_ASSOCIATION );
     emit progress(100);
-    delete responses;
     return false;
     }
   logger.debug ( "Find succeded");
   emit progress("Find succeded");
   emit progress(50);
 
-  for ( OFListIterator(FINDResponse*) it = responses->begin(); it != responses->end(); it++ )
+  for ( OFIterator<QRResponse*> it = responses.begin(); it != responses.end(); it++ )
     {
     DcmDataset *dataset = (*it)->m_dataset;
     if ( dataset != NULL ) // the last response is always empty
@@ -366,7 +368,6 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
       d->addStudyInstanceUID ( StudyInstanceUID.c_str() );
       }
     }
-  delete responses;
 
   /* Only ask for series attributes now. This requires kicking out the rest of former query. */
   d->Query->clear();
@@ -392,11 +393,11 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
     emit progress(50 + (progressRatio * i++));
 
     d->Query->putAndInsertString ( DCM_StudyInstanceUID, StudyInstanceUID.toStdString().c_str() );
-    responses = new FINDResponses();
-    status = d->SCU.sendFINDRequest ( presentationContext, d->Query, responses );
+    OFList<QRResponse *> responses;
+    status = d->SCU.sendFINDRequest ( presentationContext, d->Query, &responses );
     if ( status.good() )
       {
-      for ( OFListIterator(FINDResponse*) it = responses->begin(); it != responses->end(); it++ )
+      for ( OFIterator<QRResponse*> it = responses.begin(); it != responses.end(); it++ )
         {
         DcmDataset *dataset = (*it)->m_dataset;
         if ( dataset != NULL )
@@ -413,7 +414,6 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
       emit progress(QString("Find on Series level failed for Study: ") + StudyInstanceUID);
       }
     emit progress(50 + (progressRatio * i++));
-    delete responses;
     }
   d->SCU.closeAssociation ( DCMSCU_RELEASE_ASSOCIATION );
   emit progress(100);

+ 39 - 78
Libs/DICOM/Core/ctkDICOMRetrieve.cpp

@@ -54,7 +54,10 @@
 #include <dcmtk/dcmdata/dcrledrg.h>  /* for DcmRLEDecoderRegistration */
 #include <dcmtk/dcmdata/dcrleerg.h>  /* for DcmRLEEncoderRegistration */
 
-#include <dcmtk/dcmnet/scu.h>
+// NOTE: using ctk stand-in class for now - switch back
+// to dcmtk's scu.h when cget support is in a release version
+//#include <dcmtk/dcmnet/scu.h>
+#include <ctkDcmSCU.h>
 
 #include "dcmtk/oflog/oflog.h"
 
@@ -69,7 +72,7 @@ public:
   bool          KeepAssociationOpen;
   bool          ConnectionParamsChanged;
   QSharedPointer<ctkDICOMDatabase> RetrieveDatabase;
-  DcmSCU        scu;
+  ctkDcmSCU        SCU;
   QString MoveDestinationAETitle;
   // do the retrieve, handling both series and study retrieves
   enum RetrieveType { RetrieveSeries, RetrieveStudy };
@@ -85,21 +88,21 @@ public:
 ctkDICOMRetrievePrivate::ctkDICOMRetrievePrivate()
 {
   this->RetrieveDatabase = QSharedPointer<ctkDICOMDatabase> (0);
-  KeepAssociationOpen = true;
-  ConnectionParamsChanged = false;
+  this->KeepAssociationOpen = true;
+  this->ConnectionParamsChanged = false;
   logger.info ( "Setting Transfer Syntaxes" );
   OFList<OFString> transferSyntaxes;
   transferSyntaxes.push_back ( UID_LittleEndianExplicitTransferSyntax );
   transferSyntaxes.push_back ( UID_BigEndianExplicitTransferSyntax );
   transferSyntaxes.push_back ( UID_LittleEndianImplicitTransferSyntax );
-  scu.addPresentationContext ( UID_MOVEStudyRootQueryRetrieveInformationModel, transferSyntaxes );
+  this->SCU.addPresentationContext ( UID_MOVEStudyRootQueryRetrieveInformationModel, transferSyntaxes );
 }
 
 //------------------------------------------------------------------------------
 ctkDICOMRetrievePrivate::~ctkDICOMRetrievePrivate()
 {
   // At least now be kind to the server and release association
-  scu.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
+  this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
 }
 
 //------------------------------------------------------------------------------
@@ -126,15 +129,15 @@ bool ctkDICOMRetrievePrivate::retrieve ( const QString& studyInstanceUID,
   DcmRLEDecoderRegistration::registerCodecs();
 
   // If we like to query another server than before, be sure to disconnect first
-  if (scu.isConnected() && ConnectionParamsChanged)
+  if (this->SCU.isConnected() && this->ConnectionParamsChanged)
   {
-    scu.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
+    this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
   }
   // Connect to server if not already connected
-  if (!scu.isConnected())
+  if (!this->SCU.isConnected())
     {
     // Check and initialize networking parameters in DCMTK
-    if ( !scu.initNetwork().good() )
+    if ( !this->SCU.initNetwork().good() )
       {
       logger.error ( "Error initializing the network" );
       return false;
@@ -142,14 +145,14 @@ bool ctkDICOMRetrievePrivate::retrieve ( const QString& studyInstanceUID,
     // Negotiate (i.e. start the) association
     logger.debug ( "Negotiating Association" );
 
-    if ( !scu.negotiateAssociation().good() )
+    if ( !this->SCU.negotiateAssociation().good() )
       {
       logger.error ( "Error negotiating association" );
       return false;;
       }
     }
 
-  ConnectionParamsChanged = false;
+  this->ConnectionParamsChanged = false;
   // Setup query about what to be received from the PACS
   logger.debug ( "Setting Retrieve Parameters" );
   DcmDataset *retrieveParameters = new DcmDataset();
@@ -168,22 +171,22 @@ bool ctkDICOMRetrievePrivate::retrieve ( const QString& studyInstanceUID,
 
   // Issue request
   logger.debug ( "Sending Move Request" );
-  MOVEResponses responses;
-  T_ASC_PresentationContextID presID = scu.findPresentationContextID(UID_MOVEStudyRootQueryRetrieveInformationModel, "" /* don't care about transfer syntax */ );
+  OFList<RetrieveResponse*> responses;
+  T_ASC_PresentationContextID presID = this->SCU.findPresentationContextID(UID_MOVEStudyRootQueryRetrieveInformationModel, "" /* don't care about transfer syntax */ );
   if (presID == 0)
     {
     logger.error ( "MOVE Request failed: No valid Study Root MOVE Presentation Context available" );
-    if (!KeepAssociationOpen)
+    if (!this->KeepAssociationOpen)
       {
-      scu.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
+      this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
       }
     return false;
     }
-  OFCondition status = scu.sendMOVERequest ( presID, this->MoveDestinationAETitle.toStdString().c_str(), retrieveParameters, &responses );
+  OFCondition status = this->SCU.sendMOVERequest ( presID, this->MoveDestinationAETitle.toStdString().c_str(), retrieveParameters, &responses );
   // Close association if we do not want to explicitly keep it open
-  if (!KeepAssociationOpen)
+  if (!this->KeepAssociationOpen)
     {
-    scu.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
+    this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
     }
   // Free some (little) memory
   delete retrieveParameters;
@@ -203,9 +206,9 @@ bool ctkDICOMRetrievePrivate::retrieve ( const QString& studyInstanceUID,
    * 3) Error code, i.e. no images transferred
    * 4) Warning (one or more failures, i.e. some images transferred)
    */
-  if ( responses.numResults() == 1 )
+  if ( responses.size() == 1 )
     {
-    MOVEResponse* rsp = *responses.begin();
+    RetrieveResponse* rsp = *responses.begin();
     logger.debug ( "MOVE response receveid with status: " + QString(DU_cmoveStatusString(rsp->m_status)) );
     if ((rsp->m_status == STATUS_Success) || (rsp->m_status == STATUS_MOVE_Warning_SubOperationsCompleteOneOrMoreFailures))
       {
@@ -230,9 +233,9 @@ bool ctkDICOMRetrievePrivate::retrieve ( const QString& studyInstanceUID,
       throw std::runtime_error( statusDetail.toStdString() );
       }
     }
-  // Select the last MOVE response to output meaningful status information
-  OFListIterator(MOVEResponse*) it = responses.begin();
-  Uint32 numResults = responses.numResults();
+    // Select the last MOVE response to output meaningful status information
+    OFIterator<RetrieveResponse*> it = responses.begin();
+  Uint32 numResults = responses.size();
   for (Uint32 i = 1; i < numResults; i++)
     {
     it++;
@@ -242,48 +245,6 @@ bool ctkDICOMRetrievePrivate::retrieve ( const QString& studyInstanceUID,
     + QString::number(static_cast<unsigned int>((*it)->m_numberOfWarningSubops))   + " images transferred with warning, and\n"
     + QString::number(static_cast<unsigned int>((*it)->m_numberOfFailedSubops))    + " images transfers failed");
 
-  /* Comment from Michael: The code below does not make sense. Using MOVE you never
-   * receive the image here but only status information; thus, rsp->m_dataset is _not_
-   * an image. I leave it inside since it might be moved to a location which makes more
-   * sense.
-   */
-
- // for ( OFListIterator(MOVEResponse*) it = responses.begin(); it != responses.end(); it++ )
- // {
- //    DcmDataset *dataset = (*it)->m_dataset;
- //   if ( dataset != NULL )
- //   {
- //     logger.debug ( "Got a valid dataset" );
- //     // Save in correct directory
- //     E_TransferSyntax output_transfersyntax = dataset->getOriginalXfer();
- //     dataset->chooseRepresentation( output_transfersyntax, NULL );
- //
- //     if ( !dataset->canWriteXfer( output_transfersyntax ) )
- //     {
- //       // Pick EXS_LittleEndianExplicit as our default
- //       output_transfersyntax = EXS_LittleEndianExplicit;
- //     }
- //
- //     DcmXfer opt_oxferSyn( output_transfersyntax );
- //     if ( !dataset->chooseRepresentation( opt_oxferSyn.getXfer(), NULL ).bad() )
- //     {
- //       DcmFileFormat fileformat( dataset );
- //
- //       // Follow dcmdjpeg example
- //       OFString SOPInstanceUID;
- //       dataset->findAndGetOFString ( DCM_SOPInstanceUID, SOPInstanceUID );
- //       QFileInfo fi ( directory, QString ( SOPInstanceUID.c_str() ) );
- //       logger.debug ( "Saving file: " + fi.absoluteFilePath() );
- //       status = fileformat.saveFile ( fi.absoluteFilePath().toStdString().c_str(), opt_oxferSyn.getXfer() );
- //       if ( !status.good() )
- //       {
- //         logger.error ( "Error saving file: " + fi.absoluteFilePath() + " Error is " + status.text() );
- //       }
- //      // Insert into our local database
- //       RetrieveDatabase->insert( dataset, true );
- //     }
- //   }
- // }
   return true;
 }
 
@@ -306,9 +267,9 @@ ctkDICOMRetrieve::~ctkDICOMRetrieve()
 void ctkDICOMRetrieve::setCallingAETitle( const QString& callingAETitle )
 {
   Q_D(ctkDICOMRetrieve);
-  if (strcmp(callingAETitle.toStdString().c_str(), d->scu.getAETitle().c_str()))
+  if (strcmp(callingAETitle.toStdString().c_str(), d->SCU.getAETitle().c_str()))
   {
-    d->scu.setAETitle(callingAETitle.toStdString().c_str());
+    d->SCU.setAETitle(callingAETitle.toStdString().c_str());
     d->ConnectionParamsChanged = true;
   }
 }
@@ -317,16 +278,16 @@ void ctkDICOMRetrieve::setCallingAETitle( const QString& callingAETitle )
 QString ctkDICOMRetrieve::callingAETitle() const
 {
   Q_D(const ctkDICOMRetrieve);
-  return d->scu.getAETitle().c_str();
+  return d->SCU.getAETitle().c_str();
 }
 
 //------------------------------------------------------------------------------
 void ctkDICOMRetrieve::setCalledAETitle( const QString& calledAETitle )
 {
   Q_D(ctkDICOMRetrieve);
-  if (strcmp(calledAETitle.toStdString().c_str(),d->scu.getPeerAETitle().c_str()))
+  if (strcmp(calledAETitle.toStdString().c_str(),d->SCU.getPeerAETitle().c_str()))
   {
-    d->scu.setPeerAETitle(calledAETitle.toStdString().c_str());
+    d->SCU.setPeerAETitle(calledAETitle.toStdString().c_str());
     d->ConnectionParamsChanged = true;
   }
 }
@@ -335,16 +296,16 @@ void ctkDICOMRetrieve::setCalledAETitle( const QString& calledAETitle )
 QString ctkDICOMRetrieve::calledAETitle()const
 {
   Q_D(const ctkDICOMRetrieve);
-  return d->scu.getPeerAETitle().c_str();
+  return d->SCU.getPeerAETitle().c_str();
 }
 
 //------------------------------------------------------------------------------
 void ctkDICOMRetrieve::setHost( const QString& host )
 {
   Q_D(ctkDICOMRetrieve);
-  if (strcmp(host.toStdString().c_str(), d->scu.getPeerHostName().c_str()))
+  if (strcmp(host.toStdString().c_str(), d->SCU.getPeerHostName().c_str()))
   {
-    d->scu.setPeerHostName(host.toStdString().c_str());
+    d->SCU.setPeerHostName(host.toStdString().c_str());
     d->ConnectionParamsChanged = true;
   }
 }
@@ -353,16 +314,16 @@ void ctkDICOMRetrieve::setHost( const QString& host )
 QString ctkDICOMRetrieve::host()const
 {
   Q_D(const ctkDICOMRetrieve);
-  return d->scu.getPeerHostName().c_str();
+  return d->SCU.getPeerHostName().c_str();
 }
 
 //------------------------------------------------------------------------------
 void ctkDICOMRetrieve::setCalledPort( int port )
 {
   Q_D(ctkDICOMRetrieve);
-  if (d->scu.getPeerPort() != port)
+  if (d->SCU.getPeerPort() != port)
   {
-    d->scu.setPeerPort(port);
+    d->SCU.setPeerPort(port);
     d->ConnectionParamsChanged = true;
   }
 }
@@ -371,7 +332,7 @@ void ctkDICOMRetrieve::setCalledPort( int port )
 int ctkDICOMRetrieve::calledPort()const
 {
   Q_D(const ctkDICOMRetrieve);
-  return d->scu.getPeerPort();
+  return d->SCU.getPeerPort();
 }
 
 //------------------------------------------------------------------------------

File diff suppressed because it is too large
+ 2630 - 0
Libs/DICOM/Core/ctkDcmSCU.cc


File diff suppressed because it is too large
+ 1186 - 0
Libs/DICOM/Core/ctkDcmSCU.h