7 #include "fwPacsIO/SeriesEnquirer.hpp" 9 #include "fwPacsIO/exceptions/NegociateAssociationFailure.hpp" 10 #include "fwPacsIO/exceptions/NetworkInitializationFailure.hpp" 11 #include "fwPacsIO/exceptions/PresentationContextMissing.hpp" 12 #include "fwPacsIO/exceptions/RequestFailure.hpp" 13 #include "fwPacsIO/exceptions/TagMissing.hpp" 17 #include <fwDcmtkTools/Dictionary.hpp> 19 #include <fwTools/System.hpp> 21 #include <boost/filesystem/operations.hpp> 22 #include <boost/foreach.hpp> 24 #include <dcmtk/config/osconfig.h> 25 #include <dcmtk/dcmdata/dcfilefo.h> 26 #include <dcmtk/dcmnet/diutil.h> 31 const ::fwCom::Slots::SlotKeyType SeriesEnquirer::s_PROGRESS_CALLBACK_SLOT =
"CGetProgressCallback";
34 m_moveApplicationTitle(
""),
53 pc = this->findPresentationContextID(sopClass, UID_LittleEndianExplicitTransferSyntax);
56 pc = this->findPresentationContextID(sopClass, UID_BigEndianExplicitTransferSyntax);
60 pc = this->findPresentationContextID(sopClass, UID_LittleEndianImplicitTransferSyntax);
68 unsigned short peerPort,
const std::string& peerApplicationTitle,
69 const std::string& moveApplicationTitle,
70 ProgressCallbackSlotType::sptr progressCallback)
80 if (!
m_path.empty() && !::boost::filesystem::exists(
m_path))
82 ::boost::filesystem::create_directories(
m_path);
89 this->setAETitle(applicationTitle.c_str());
90 this->setPeerHostName(peerHostName.c_str());
91 this->setPeerPort(peerPort);
92 this->setPeerAETitle(peerApplicationTitle.c_str());
95 this->clearPresentationContexts();
98 OFList < OFString > transferSyntaxes;
99 transferSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);
100 transferSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);
101 transferSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);
102 transferSyntaxes.push_back(UID_JPEGProcess1TransferSyntax);
103 transferSyntaxes.push_back(UID_JPEGProcess2_4TransferSyntax);
104 transferSyntaxes.push_back(UID_JPEGProcess3_5TransferSyntax);
105 transferSyntaxes.push_back(UID_JPEGProcess6_8TransferSyntax);
106 transferSyntaxes.push_back(UID_JPEGProcess7_9TransferSyntax);
107 transferSyntaxes.push_back(UID_JPEGProcess10_12TransferSyntax);
108 transferSyntaxes.push_back(UID_JPEGProcess11_13TransferSyntax);
109 transferSyntaxes.push_back(UID_JPEGProcess14TransferSyntax);
110 transferSyntaxes.push_back(UID_JPEGProcess15TransferSyntax);
111 transferSyntaxes.push_back(UID_JPEGProcess16_18TransferSyntax);
112 transferSyntaxes.push_back(UID_JPEGProcess17_19TransferSyntax);
113 transferSyntaxes.push_back(UID_JPEGProcess20_22TransferSyntax);
114 transferSyntaxes.push_back(UID_JPEGProcess21_23TransferSyntax);
115 transferSyntaxes.push_back(UID_JPEGProcess24_26TransferSyntax);
116 transferSyntaxes.push_back(UID_JPEGProcess25_27TransferSyntax);
117 transferSyntaxes.push_back(UID_JPEGProcess28TransferSyntax);
118 transferSyntaxes.push_back(UID_JPEGProcess29TransferSyntax);
119 transferSyntaxes.push_back(UID_JPEGProcess14SV1TransferSyntax);
120 transferSyntaxes.push_back(UID_JPEGLSLosslessTransferSyntax);
121 transferSyntaxes.push_back(UID_JPEGLSLossyTransferSyntax);
122 transferSyntaxes.push_back(UID_RLELosslessTransferSyntax);
123 transferSyntaxes.push_back(UID_DeflatedExplicitVRLittleEndianTransferSyntax);
124 transferSyntaxes.push_back(UID_JPEG2000LosslessOnlyTransferSyntax);
125 transferSyntaxes.push_back(UID_JPEG2000TransferSyntax);
126 transferSyntaxes.push_back(UID_MPEG2MainProfileAtMainLevelTransferSyntax);
127 transferSyntaxes.push_back(UID_MPEG2MainProfileAtHighLevelTransferSyntax);
128 transferSyntaxes.push_back(UID_JPEG2000Part2MulticomponentImageCompressionLosslessOnlyTransferSyntax);
129 transferSyntaxes.push_back(UID_JPEG2000Part2MulticomponentImageCompressionTransferSyntax);
130 transferSyntaxes.push_back(UID_JPIPReferencedTransferSyntax);
131 transferSyntaxes.push_back(UID_JPIPReferencedDeflateTransferSyntax);
132 transferSyntaxes.push_back(UID_RFC2557MIMEEncapsulationTransferSyntax);
133 transferSyntaxes.push_back(UID_XMLEncodingTransferSyntax);
136 this->addPresentationContext(UID_VerificationSOPClass, transferSyntaxes);
139 this->addPresentationContext(UID_FINDStudyRootQueryRetrieveInformationModel, transferSyntaxes);
140 this->addPresentationContext(UID_MOVEStudyRootQueryRetrieveInformationModel, transferSyntaxes);
141 this->addPresentationContext(UID_GETStudyRootQueryRetrieveInformationModel, transferSyntaxes);
144 for (Uint16 j = 0; j < numberOfDcmLongSCUStorageSOPClassUIDs; j++)
146 this->addPresentationContext(dcmLongSCUStorageSOPClassUIDs[j], transferSyntaxes, ASC_SC_ROLE_SCP);
156 OFCondition result = this->initNetwork();
159 const std::string msg =
"Unable to set up the network: " + std::string(result.text());
160 throw ::fwPacsIO::exceptions::NetworkInitializationFailure(msg);
164 result = this->negotiateAssociation();
167 const std::string msg =
"Unable to negotiate association: " + std::string(result.text());
168 throw ::fwPacsIO::exceptions::NegociateAssociationFailure(msg);
179 this->closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
186 return this->isConnected();
193 return this->sendECHORequest(0).good();
200 OFList< QRResponse* > findResponses;
203 T_ASC_PresentationContextID presID = this->
findUncompressedPC(UID_FINDStudyRootQueryRetrieveInformationModel);
206 const std::string msg =
"There is no uncompressed presentation context for Study Root FIND";
207 throw ::fwPacsIO::exceptions::PresentationContextMissing(msg);
211 OFCondition result = this->sendFINDRequest(presID, &dataset, &findResponses);
213 return findResponses;
221 SLM_ASSERT(
"The path where to store the series is not set.", !
m_path.empty());
225 T_ASC_PresentationContextID presID = this->
findUncompressedPC(UID_MOVEStudyRootQueryRetrieveInformationModel);
226 SLM_WARN_IF(
"There is no uncompressed presentation context for Study Root MOVE", presID == 0);
230 OFList< RetrieveResponse* > dataResponse;
239 SLM_ASSERT(
"The path where to store the series is not set.", !
m_path.empty());
242 T_ASC_PresentationContextID presID = this->
findUncompressedPC(UID_GETStudyRootQueryRetrieveInformationModel);
246 SLM_WARN(
"There is no uncompressed presentation context for Study Root GET");
251 OFList< RetrieveResponse* > dataResponse;
252 return this->sendCGETRequest(presID, &dataset, &dataResponse);
260 T_ASC_PresentationContextID presID = this->
findUncompressedPC(UID_MOVEStudyRootQueryRetrieveInformationModel);
264 SLM_WARN(
"There is no uncompressed presentation context for Study Root GET");
267 Uint16 rspStatusCode;
268 OFCondition result = this->sendSTORERequest(presID, OFString(path.string().c_str()), 0, rspStatusCode);
269 OSLM_WARN(
"PACS RESPONSE :" << rspStatusCode);
278 T_ASC_PresentationContextID presID = this->
findUncompressedPC(UID_MOVEStudyRootQueryRetrieveInformationModel);
282 SLM_WARN(
"There is no uncompressed presentation context for Study Root GET");
285 Uint16 rspStatusCode;
287 DcmDataset* datasetPtr =
const_cast<DcmDataset*
>(dataset.get());
288 OFCondition result = this->sendSTORERequest(presID, OFString(
""), datasetPtr, rspStatusCode);
289 OSLM_WARN(
"PACS RESPONSE :" << rspStatusCode);
299 dataset.putAndInsertOFStringArray(DCM_QueryRetrieveLevel,
"SERIES");
300 dataset.putAndInsertOFStringArray(DCM_SeriesInstanceUID,
"");
303 std::string searchString =
"*" + name +
"*";
304 dataset.putAndInsertOFStringArray(DCM_PatientName, searchString.c_str());
308 dataset.putAndInsertOFStringArray(DCM_PatientID,
"");
309 dataset.putAndInsertOFStringArray(DCM_PatientBirthDate,
"");
310 dataset.putAndInsertOFStringArray(DCM_PatientSex,
"");
311 dataset.putAndInsertOFStringArray(DCM_StudyInstanceUID,
"");
312 dataset.putAndInsertOFStringArray(DCM_StudyDate,
"");
313 dataset.putAndInsertOFStringArray(DCM_StudyTime,
"");
314 dataset.putAndInsertOFStringArray(DCM_ReferringPhysicianName,
"");
315 dataset.putAndInsertOFStringArray(DCM_StudyDescription,
"");
316 dataset.putAndInsertOFStringArray(DCM_PatientAge,
"");
317 dataset.putAndInsertOFStringArray(DCM_InstitutionName,
"");
318 dataset.putAndInsertOFStringArray(DCM_Modality,
"");
319 dataset.putAndInsertOFStringArray(DCM_SeriesDate,
"");
320 dataset.putAndInsertOFStringArray(DCM_SeriesTime,
"");
321 dataset.putAndInsertOFStringArray(DCM_SeriesDescription,
"");
322 dataset.putAndInsertOFStringArray(DCM_PerformingPhysicianName,
"");
325 dataset.putAndInsertOFStringArray(DCM_NumberOfSeriesRelatedInstances,
"");
336 dataset.putAndInsertOFStringArray(DCM_QueryRetrieveLevel,
"SERIES");
337 dataset.putAndInsertOFStringArray(DCM_SeriesInstanceUID,
"");
340 std::string searchString = fromDate +
"-" + toDate;
341 dataset.putAndInsertOFStringArray(DCM_StudyDate, searchString.c_str());
344 dataset.putAndInsertOFStringArray(DCM_PatientName,
"");
345 dataset.putAndInsertOFStringArray(DCM_PatientID,
"");
346 dataset.putAndInsertOFStringArray(DCM_PatientBirthDate,
"");
347 dataset.putAndInsertOFStringArray(DCM_PatientSex,
"");
348 dataset.putAndInsertOFStringArray(DCM_StudyInstanceUID,
"");
350 dataset.putAndInsertOFStringArray(DCM_StudyTime,
"");
351 dataset.putAndInsertOFStringArray(DCM_ReferringPhysicianName,
"");
352 dataset.putAndInsertOFStringArray(DCM_StudyDescription,
"");
353 dataset.putAndInsertOFStringArray(DCM_PatientAge,
"");
354 dataset.putAndInsertOFStringArray(DCM_InstitutionName,
"");
355 dataset.putAndInsertOFStringArray(DCM_Modality,
"");
356 dataset.putAndInsertOFStringArray(DCM_SeriesDate,
"");
357 dataset.putAndInsertOFStringArray(DCM_SeriesTime,
"");
358 dataset.putAndInsertOFStringArray(DCM_SeriesDescription,
"");
359 dataset.putAndInsertOFStringArray(DCM_PerformingPhysicianName,
"");
362 dataset.putAndInsertOFStringArray(DCM_NumberOfSeriesRelatedInstances,
"");
373 dataset.putAndInsertOFStringArray(DCM_QueryRetrieveLevel,
"SERIES");
376 dataset.putAndInsertOFStringArray(DCM_SeriesInstanceUID, uid.c_str());
379 dataset.putAndInsertOFStringArray(DCM_PatientName,
"");
380 dataset.putAndInsertOFStringArray(DCM_PatientID,
"");
381 dataset.putAndInsertOFStringArray(DCM_PatientBirthDate,
"");
382 dataset.putAndInsertOFStringArray(DCM_PatientSex,
"");
383 dataset.putAndInsertOFStringArray(DCM_StudyInstanceUID,
"");
384 dataset.putAndInsertOFStringArray(DCM_StudyDate,
"");
385 dataset.putAndInsertOFStringArray(DCM_StudyTime,
"");
386 dataset.putAndInsertOFStringArray(DCM_ReferringPhysicianName,
"");
387 dataset.putAndInsertOFStringArray(DCM_StudyDescription,
"");
388 dataset.putAndInsertOFStringArray(DCM_PatientAge,
"");
389 dataset.putAndInsertOFStringArray(DCM_InstitutionName,
"");
390 dataset.putAndInsertOFStringArray(DCM_Modality,
"");
391 dataset.putAndInsertOFStringArray(DCM_SeriesDate,
"");
392 dataset.putAndInsertOFStringArray(DCM_SeriesTime,
"");
393 dataset.putAndInsertOFStringArray(DCM_SeriesDescription,
"");
394 dataset.putAndInsertOFStringArray(DCM_PerformingPhysicianName,
"");
397 dataset.putAndInsertOFStringArray(DCM_NumberOfSeriesRelatedInstances,
"");
408 dataset.putAndInsertOFStringArray(DCM_QueryRetrieveLevel,
"IMAGE");
409 dataset.putAndInsertOFStringArray(DCM_SeriesInstanceUID, seriesInstanceUID.c_str());
410 dataset.putAndInsertOFStringArray(DCM_SOPInstanceUID,
"");
411 std::stringstream ss;
412 ss << instanceNumber;
413 dataset.putAndInsertOFStringArray(DCM_InstanceNumber, ss.str().c_str());
416 OFIterator< QRResponse* > it = responses.begin();
417 std::string sopInstanceUID =
"";
418 if(it != responses.end() && (*it)->m_dataset)
421 (*it)->m_dataset->findAndGetOFStringArray(DCM_SOPInstanceUID, sop);
422 sopInstanceUID = sop.c_str();
426 while (!responses.empty())
428 delete responses.front();
429 responses.pop_front();
432 return sopInstanceUID;
446 for( std::string seriesInstanceUID: instanceUIDContainer )
448 dataset.putAndInsertOFStringArray(DCM_QueryRetrieveLevel,
"SERIES");
449 dataset.putAndInsertOFStringArray(DCM_SeriesInstanceUID, seriesInstanceUID.c_str());
456 SLM_TRACE(
"Received series " + seriesInstanceUID);
460 const std::string msg =
"Unable to send a C-MOVE request to the server. " 461 "(Series instance UID =" + std::string(seriesInstanceUID.c_str()) +
") : " 462 + std::string(result.text());
463 throw ::fwPacsIO::exceptions::RequestFailure(msg);
479 for( std::string seriesInstanceUID: instanceUIDContainer )
481 dataset.putAndInsertOFStringArray(DCM_QueryRetrieveLevel,
"SERIES");
482 dataset.putAndInsertOFStringArray(DCM_SeriesInstanceUID, seriesInstanceUID.c_str());
489 SLM_TRACE(
"Received series " + seriesInstanceUID);
493 const std::string msg =
"Unable to send a C-GET request to the server. " 494 "(Series instance UID =" + std::string(seriesInstanceUID.c_str()) +
") : " 495 + std::string(result.text());
496 throw ::fwPacsIO::exceptions::RequestFailure(msg);
504 const std::string& sopInstanceUID)
511 dataset.putAndInsertOFStringArray(DCM_QueryRetrieveLevel,
"IMAGE");
512 dataset.putAndInsertOFStringArray(DCM_SeriesInstanceUID, seriesInstanceUID.c_str());
514 dataset.putAndInsertOFStringArray(DCM_SOPInstanceUID, sopInstanceUID.c_str());
515 dataset.putAndInsertOFStringArray(DCM_InstanceNumber,
"");
522 SLM_TRACE(
"Received instance " + seriesInstanceUID +
" - " + sopInstanceUID);
526 const std::string msg =
"Unable to send a C-MOVE request to the server. " 527 "(Series instance UID =" + std::string(seriesInstanceUID.c_str()) +
") : " 528 + std::string(result.text());
529 throw ::fwPacsIO::exceptions::RequestFailure(msg);
536 const std::string& sopInstanceUID)
543 dataset.putAndInsertOFStringArray(DCM_QueryRetrieveLevel,
"IMAGE");
544 dataset.putAndInsertOFStringArray(DCM_SeriesInstanceUID, seriesInstanceUID.c_str());
546 dataset.putAndInsertOFStringArray(DCM_SOPInstanceUID, sopInstanceUID.c_str());
547 dataset.putAndInsertOFStringArray(DCM_InstanceNumber,
"");
554 SLM_TRACE(
"Received instance " + seriesInstanceUID +
" - " + sopInstanceUID);
558 const std::string msg =
"Unable to send a C-GET request to the server. " 559 "(Series instance UID =" + std::string(seriesInstanceUID.c_str()) +
") : " 560 + std::string(result.text());
561 throw ::fwPacsIO::exceptions::RequestFailure(msg);
575 for(const ::boost::filesystem::path& path: pathContainer)
585 const std::string msg =
"Unable to send a C-STORE request to the server : " + std::string(result.text());
586 throw ::fwPacsIO::exceptions::RequestFailure(msg);
606 for(
const auto& dataset : datasetContainer)
616 const std::string msg =
"Unable to send a C-STORE request to the server : " + std::string(result.text());
617 throw ::fwPacsIO::exceptions::RequestFailure(msg);
631 const T_ASC_PresentationContextID presID, RetrieveResponse* response, OFBool& waitForNextResponse)
633 OFCondition result = DcmSCU::handleMOVEResponse(presID, response, waitForNextResponse);
636 bool error = (response->m_status != STATUS_Success) && (response->m_status != STATUS_Pending);
641 const std::string msg =
"Unable to perform a C-MOVE operation.";
642 throw ::fwPacsIO::exceptions::RequestFailure(msg);
651 const T_ASC_PresentationContextID presID, DcmDataset* incomingObject,
652 OFBool& continueCGETSession, Uint16& cStoreReturnStatus)
656 if (incomingObject != NULL)
660 if(incomingObject->findAndGetOFStringArray(DCM_SeriesInstanceUID, seriesID).good())
662 SLM_TRACE(
"Series Instance UID: " + std::string(seriesID.c_str()));
667 if (incomingObject->findAndGetOFStringArray(DCM_SOPInstanceUID, iname).good())
669 SLM_TRACE(
"SOP Instance UID: " + std::string(iname.c_str()));
673 ::boost::filesystem::path seriesPath = ::boost::filesystem::path(
m_path.string() + seriesID.c_str() +
"/");
674 if (!::boost::filesystem::exists(seriesPath))
676 ::boost::filesystem::create_directories(seriesPath);
680 std::string filePath = seriesPath.string() + iname.c_str();
681 DcmFileFormat fileFormat(incomingObject);
682 fileFormat.saveFile(filePath.c_str(), EXS_Unknown, EET_UndefinedLength,
683 EGL_recalcGL, EPD_noChange, 0, 0, EWM_createNewMeta);
FWPACSIO_API void pullSeriesUsingGetRetrieveMethod(InstanceUIDContainer instanceUIDContainer)
Pull series using C-GET requests.
FWPACSIO_API OFList< QRResponse * > findSeriesByPatientName(const std::string &name)
Find series by patient name.
virtual FWPACSIO_API OFCondition handleSTORERequest(const T_ASC_PresentationContextID presID, DcmDataset *incomingObject, OFBool &continueCGETSession, Uint16 &cStoreReturnStatus) override
Handle STORE Request (Override)
FWPACSIO_API OFList< QRResponse * > findSeriesByDate(const std::string &fromDate, const std::string &toDate)
Find series by study date.
ProgressCallbackSlotType::sptr m_progressCallback
Progress callback slot.
fwPacsIO contains classes used to communicate with a PACS.
FWPACSIO_API ~SeriesEnquirer()
Destructor.
FWPACSIO_API void pushSeries(const InstancePathContainer &pathContainer)
Push instances using C-STORE requests.
FWPACSIO_API OFList< QRResponse * > sendFindRequest(DcmDataset dataset)
Send Find Request.
::boost::filesystem::path m_path
Path where the files must be saved.
#define SLM_WARN(message)
FWPACSIO_API bool isConnectedToPacs() const
Return true if there is an existing association.
FWPACSIO_API bool pingPacs()
Assemble and send C-ECHO request.
virtual FWPACSIO_API OFCondition handleMOVEResponse(const T_ASC_PresentationContextID presID, RetrieveResponse *response, OFBool &waitForNextResponse) override
Handle MOVE Response (Override)
FWPACSIO_API void initialize(const std::string &applicationTitle, const std::string &peerHostName, unsigned short peerPort, const std::string &peerApplicationTitle, const std::string &moveApplicationTitle="", ProgressCallbackSlotType::sptr progressCallback=ProgressCallbackSlotType::sptr())
Initialize the connection.
FWPACSIO_API void pullSeriesUsingMoveRetrieveMethod(InstanceUIDContainer instanceUIDContainer)
Pull series using C-MOVE requests.
FWPACSIO_API SeriesEnquirer()
Constructor.
FWPACSIO_API void disconnect()
Release association.
#define OSLM_WARN(message)
#define SLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
FWPACSIO_API std::string findSOPInstanceUID(const std::string &seriesInstanceUID, unsigned int instanceNumber)
Find SOPInstanceUID of the specified instance.
FWPACSIO_API bool connect()
Negotiate Association.
FWPACSIO_API OFCondition sendMoveRequest(DcmDataset dataset)
Send Move Request.
#define SLM_TRACE(message)
FWPACSIO_API OFCondition sendStoreRequest(const ::boost::filesystem::path &path)
Send Store Request.
FWPACSIO_API OFCondition sendGetRequest(DcmDataset dataset)
Send Get Request.
std::string m_moveApplicationTitle
MOVE destination AE Title.
FWPACSIO_API void pullInstanceUsingGetRetrieveMethod(const std::string &seriesInstanceUID, const std::string &sopInstanceUID)
Pull instance using C-GET requests.
unsigned int m_instanceIndex
Dowloaded instance index.
FWPACSIO_API void pullInstanceUsingMoveRetrieveMethod(const std::string &seriesInstanceUID, const std::string &sopInstanceUID)
Pull instance using C-MOVE requests.
This file defines SpyLog macros. These macros are used to log messages to a file or to the console du...
FWPACSIO_API Uint8 findUncompressedPC(const OFString &sopClass)
Find uncompressed presentation context.
#define SLM_WARN_IF(message, cond)
FWPACSIO_API OFList< QRResponse * > findSeriesByUID(const std::string &uid)
Find series by series UID.