3
* $Id: dicomassociation.cpp 3654 2011-04-06 11:00:08Z tovar $
6
* Copyright 2008-10 MetaEmotion S.L. All rights reserved.
7
* http://ginkgo-cadx.com
9
* This file is licensed under LGPL v3 license.
10
* See License.txt for details
12
* Code adapted from Aeskulap
15
#include <api/icontroladorlog.h>
16
#include <main/controllers/controladorlog.h>
17
#include "dicomassociation.h"
18
#include "dicomnetwork.h"
23
#ifdef MACRO_QUE_ESTORBA
24
#define verify MACRO_QUE_ESTORBA
27
#include <dcmtk/dcmdata/dcdeftag.h>
28
#include <dcmtk/dcmdata/dcuid.h> /* for dcmtk version name */
29
#include <dcmtk/dcmjpeg/djdecode.h> /* for dcmjpeg decoders */
30
#include <dcmtk/dcmjpeg/djencode.h> /* for dcmjpeg encoders */
31
#include <dcmtk/dcmjpeg/djrplol.h> /* for DJ_RPLossless */
32
#include <dcmtk/dcmjpeg/djrploss.h> /* for DJ_RPLossy */
33
#include <dcmtk/dcmjpeg/dipijpeg.h> /* for dcmimage JPEG plugin */
34
#include <dcmtk/dcmimage/diregist.h> /* include to support color images */
35
#include <dcmtk/ofstd/ofcmdln.h>
36
#include <dcmtk/dcmnet/diutil.h>
38
#include <dcmtk/dcmjpeg/djencode.h>
39
#include <dcmtk/dcmjpeg/djdecode.h>
40
#include <dcmtk/dcmjpeg/djrplol.h>
41
#include <dcmtk/dcmjpeg/djrploss.h>
43
#ifdef MACRO_QUE_ESTORBA
44
#define verify MACRO_QUE_ESTORBA
48
const char* Association::AllTransferSyntaxes[] = {
49
UID_LittleEndianImplicitTransferSyntax, /// Implicit VR Little Endian: Default Transfer Syntax for DICOM
50
UID_LittleEndianExplicitTransferSyntax, /// Explicit VR Little Endian
51
UID_BigEndianExplicitTransferSyntax, /// Explicit VR Big Endian
52
UID_DeflatedExplicitVRLittleEndianTransferSyntax, /// Deflated Explicit VR Little Endian
53
UID_JPEGProcess1TransferSyntax, /// JPEG Baseline (Process 1): Default Transfer Syntax for Lossy JPEG 8 Bit Image Compression
54
UID_JPEGProcess2_4TransferSyntax, /// JPEG Extended (Process 2 & 4): Default Transfer Syntax for Lossy JPEG 12 Bit Image Compression (Process 4 only)
55
// UID_JPEGProcess3_5TransferSyntax, /// JPEG Extended (Process 3 & 5) - RETIRED
56
// UID_JPEGProcess6_8TransferSyntax, /// JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8) - RETIRED
57
// UID_JPEGProcess7_9TransferSyntax, /// JPEG Spectral Selection, Non-Hierarchical (Process 7 & 9) - RETIRED
58
// UID_JPEGProcess10_12TransferSyntax, /// JPEG Full Progression, Non-Hierarchical (Process 10 & 12) - RETIRED
59
// UID_JPEGProcess11_13TransferSyntax, /// JPEG Full Progression, Non-Hierarchical (Process 11 & 13) - RETIRED
60
UID_JPEGProcess14TransferSyntax, /// JPEG Lossless, Non-Hierarchical (Process 14)
61
// UID_JPEGProcess15TransferSyntax, /// JPEG Lossless, Non-Hierarchical (Process 15) - RETIRED
62
// UID_JPEGProcess16_18TransferSyntax, /// JPEG Extended, Hierarchical (Process 16 & 18) - RETIRED
63
// UID_JPEGProcess17_19TransferSyntax, /// JPEG Extended, Hierarchical (Process 17 & 19) - RETIRED
64
// UID_JPEGProcess20_22TransferSyntax, /// JPEG Spectral Selection, Hierarchical (Process 20 & 22) - RETIRED
65
// UID_JPEGProcess21_23TransferSyntax, /// JPEG Spectral Selection, Hierarchical (Process 21 & 23) - RETIRED
66
// UID_JPEGProcess24_26TransferSyntax, /// JPEG Full Progression, Hierarchical (Process 24 & 26) - RETIRED
67
// UID_JPEGProcess25_27TransferSyntax, /// JPEG Full Progression, Hierarchical (Process 25 & 27) - RETIRED
68
// UID_JPEGProcess28TransferSyntax, /// JPEG Lossless, Hierarchical (Process 28) - RETIRED
69
// UID_JPEGProcess29TransferSyntax, /// JPEG Lossless, Hierarchical (Process 29) - RETIRED
70
UID_JPEGProcess14SV1TransferSyntax, /// JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1]): Default Transfer Syntax for Lossless JPEG Image Compression
71
UID_JPEGLSLosslessTransferSyntax, /// JPEG-LS Lossless Image Compression
72
UID_JPEGLSLossyTransferSyntax, /// JPEG-LS Lossy (Near-Lossless) Image Compression
73
UID_JPEG2000LosslessOnlyTransferSyntax, /// JPEG 2000 Image Compression (Lossless Only)
74
UID_JPEG2000TransferSyntax, /// JPEG 2000 Image Compression (Lossless or Lossy)
75
UID_JPEG2000Part2MulticomponentImageCompressionLosslessOnlyTransferSyntax, /// JPEG 2000 Part 2 Multi-component Image Compression (Lossless Only)
76
UID_JPEG2000Part2MulticomponentImageCompressionTransferSyntax, /// JPEG 2000 Part 2 Multi-component Image Compression (Lossless or Lossy)
77
UID_JPIPReferencedTransferSyntax, /// JPIP Referenced
78
UID_JPIPReferencedDeflateTransferSyntax, /// JPIP Referenced Deflate
79
UID_MPEG2MainProfileAtMainLevelTransferSyntax, /// MPEG2 Main Profile @ Main Level
80
UID_MPEG2MainProfileAtHighLevelTransferSyntax, /// MPEG2 Main Profile @ High Level
81
UID_RLELosslessTransferSyntax /// RLE Lossless
84
const unsigned int Association::AllTransferSyntaxesCount = 19;
86
Association::Association(const std::string& _ambitolog) :
87
ambitolog(_ambitolog),
88
m_pNotificadorProgreso(NULL),
89
m_abstractSyntax(NULL),
100
m_UseUserPass(false),
107
Association::~Association() {
108
// drop an existing association on shutdown
112
m_pNotificadorProgreso = NULL;
115
CONDITION Association::Drop(CONDITION cond) {
116
// tear down association
117
if (cond == DIMSE_NORMAL) {
118
/* release association */
119
cond = ASC_releaseAssociation(assoc);
121
else if (cond == DIMSE_PEERREQUESTEDRELEASE) {
122
cond = ASC_acknowledgeRelease(assoc);
124
cond = ASC_abortAssociation(assoc);
130
else if (cond == DIMSE_PEERABORTEDASSOCIATION) {
134
cond = ASC_abortAssociation(assoc);
144
void Association::Destroy() {
145
CONDITION cond = ASC_destroyAssociation(&assoc);
156
CONDITION Association::SendObject(DcmDataset *dataset) {
158
DcmDataset *statusDetail = NULL;
161
return DUL_NETWORKCLOSED;
164
T_DIMSE_C_StoreRQ req;
165
T_DIMSE_C_StoreRSP rsp;
167
// check if we SOPClass and SOPInstance in dataset
168
if (!DU_findSOPClassAndInstanceInDataSet(dataset, sopClass, sopInstance)) {
169
LOG_ERROR(ambitolog, "No se pudo encontrar el SOPClass o SOPInstanceUID en el dataset");
170
return DIMSE_BADDATA;
173
/* which presentation context should be used */
174
presId = ASC_findAcceptedPresentationContextID(assoc, sopClass);
176
const char *modalityName = dcmSOPClassUIDToModality(sopClass);
177
if (!modalityName) modalityName = dcmFindNameOfUID(sopClass);
178
if (!modalityName) modalityName = "unknown SOP class";
179
LOG_ERROR(ambitolog, "No se pudo encontrar ningún ContextID de presentación aceptado. SOPClass = " << sopClass << " Modalidad = " << modalityName);
180
return DIMSE_BADDATA;
185
bzero((char*) & req, sizeof (req));
186
req.MessageID = msgId;
187
strncpy(req.AffectedSOPClassUID, sopClass, sizeof (req.AffectedSOPClassUID));
188
strncpy(req.AffectedSOPInstanceUID, sopInstance, sizeof (req.AffectedSOPInstanceUID));
189
req.DataSetType = DIMSE_DATASET_PRESENT;
190
req.Priority = DIMSE_PRIORITY_LOW;
192
// convert to accepted transfer syntax
193
T_ASC_PresentationContext pc;
194
cond = ASC_findAcceptedPresentationContext(assoc->params, presId, &pc);
195
ASC_dumpPresentationContext(&pc, COUT);
197
DJEncoderRegistration::registerCodecs(
199
EUC_never, // UID generation (never create new UID's)
201
OFTrue); // optimize huffman table
203
DcmXfer opt_oxferSyn(pc.acceptedTransferSyntax);
204
E_TransferSyntax ori_oxferSyn = dataset->getOriginalXfer();
206
DcmXfer original_xfer(dataset->getOriginalXfer());
208
if (opt_oxferSyn.getXfer() != ori_oxferSyn) {
209
LOG_DEBUG(ambitolog, "Convirtiendo objeto a Transfer-Syntax aceptado: " << opt_oxferSyn.getXferName());
212
// create RepresentationParameter
213
DJ_RPLossless rp_lossless(6, 0);
214
DJ_RPLossy rp_lossy(70);
218
const DcmRepresentationParameter *rp = NULL;
220
if (opt_oxferSyn.getXfer() == EXS_JPEGProcess14SV1TransferSyntax || opt_oxferSyn.getXfer() == EXS_JPEGProcess14TransferSyntax) {
223
else if (opt_oxferSyn.getXfer() == EXS_JPEGProcess1TransferSyntax || opt_oxferSyn.getXfer() == EXS_JPEGProcess2_4TransferSyntax) {
229
if (original_xfer.isEncapsulated()) {
230
LOG_DEBUG(ambitolog, "El fichero DICOM ya está comprimido. Se convertirá antes a un Transfer Syntax descomprimido");
231
if (EC_Normal != dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL)) {
232
LOG_DEBUG(ambitolog, "No fué posible convertir el formato original a un Transfer Syntax descomprimido"); }
236
cond = dataset->chooseRepresentation(opt_oxferSyn.getXfer(), rp);
238
LOG_ERROR(ambitolog, "Error al elegir la representación: " << cond.text());
241
if (dataset->canWriteXfer(opt_oxferSyn.getXfer())) {
242
LOG_DEBUG(ambitolog, "El Transfer Syntax de salida (" << opt_oxferSyn.getXferName() << " puede ser escrito");
245
LOG_ERROR(ambitolog, "No se encontró ninguna conversión posible al El Transfer Syntax de salida (" << opt_oxferSyn.getXferName());
251
cond = DIMSE_storeUser(
259
(m_timeout == 0) ? DIMSE_BLOCKING : DIMSE_NONBLOCKING,
264
// increase message id
269
if (rsp.DataSetType == DIMSE_DATASET_PRESENT) {
270
LOG_DEBUG(ambitolog, "Respuesta con dataset");
273
if (statusDetail != NULL) {
274
LOG_TRACE(ambitolog, "Estado: " << DumpDataset(statusDetail));
278
if (cond != DIMSE_NORMAL) {
282
if (rsp.DimseStatus == STATUS_Success) {
286
LOG_ERROR(ambitolog, "DIMSE Status fallido: " << rsp.DimseStatus);
287
return DIMSE_BADDATA;
291
CONDITION Association::SendObject(DcmFileFormat *dcmff) {
293
return DUL_NETWORKCLOSED;
295
DcmDataset* dataset = dcmff->getDataset();
296
return SendObject(dataset);
299
void Association::Create(const std::string& title, const std::string& peer, int port, const std::string& ouraet, const char *abstractSyntax) {
300
// no connected association till now
303
// fill in parameters
304
if (abstractSyntax != NULL) {
305
m_abstractSyntax = (char*) abstractSyntax;
318
bool Association::SendEchoRequest() {
320
DcmDataset *statusDetail = NULL;
326
OFCondition cond = DIMSE_echoUser(assoc, ++msgId, DIMSE_BLOCKING, 0, &status, &statusDetail);
328
LOG_DEBUG(ambitolog, "DIMSE ECO Completado. Estado: " << DU_cstoreStatusString(status));
331
LOG_ERROR(ambitolog, "DIMSE ECO Fallido: " << cond.text());
334
if (statusDetail != NULL) {
341
bool Association::AddKey(DcmDataset *query, const DcmTagKey& tag, int value) {
342
static char temp[16];
343
#if defined(_WINDOWS)
344
sprintf_s(temp, 16, "%i", value);
346
snprintf(temp, 16, "%i", value);
348
return AddKey(query, tag, temp);
351
bool Association::AddKey(DcmDataset *query, const DcmTagKey& tag, double value, const char* format) {
352
static char temp[16];
353
#if defined(_WINDOWS)
354
sprintf_s(temp, 16, format, value);
356
snprintf(temp, 16, format, value);
358
return AddKey(query, tag, temp);
361
bool Association::AddKey(DcmItem *query, const DcmTagKey& tag, int value) {
362
static char temp[16];
363
#if defined(_WINDOWS)
364
sprintf_s(temp, 16, "%i", value);
366
snprintf(temp, 16, "%i", value);
368
return AddKey(query, tag, temp);
371
bool Association::AddKey(DcmItem *query, const DcmTagKey& tag, double value, const char* format) {
372
static char temp[16];
373
#if defined(_WINDOWS)
374
sprintf_s(temp, 16, format, value);
376
snprintf(temp, 16, format, value);
378
return AddKey(query, tag, temp);
381
bool Association::AddKey(DcmDataset *query, const DcmTagKey& t, const char* value) {
382
return AddCustomKey/*< DcmDataset >*/(query, t, value);
385
bool Association::AddKey(DcmItem *query, const DcmTagKey& t, const char* value) {
386
return AddCustomKey/*< DcmItem >*/(query, t, value);
389
bool Association::AddQueryLevel(DcmDataset *query, const std::string& level) {
390
return AddKey(query, DCM_QueryRetrieveLevel, level.c_str());
393
GIL::DICOM::DCMTK::Network* Association::GetNetwork() {
397
CONDITION Association::Connect(GIL::DICOM::DCMTK::Network *network, int pdu) {
399
return network->ConnectAssociation(this, pdu);
402
const std::string& Association::GetOurAET() {
406
const char* Association::GetKey(DcmDataset* query, const DcmTagKey& tag) {
408
static char buffer[129];
409
query->findAndGetOFString(tag, val, 0, OFTrue);
410
#if defined(_WINDOWS)
411
strncpy_s(buffer, val.c_str(), sizeof (buffer));
413
strncpy(buffer, val.c_str(), sizeof (buffer));
419
void Association::SetTimeout(int t) {
423
int Association::GetTimeout() {
427
CONDITION Association::addAllStoragePresentationContexts(T_ASC_Parameters *params, bool /*bProposeCompression*/, int /*lossy*/) {
428
unsigned int pid = 1;
430
CONDITION cond = ASC_addPresentationContext(params, pid, m_abstractSyntax, AllTransferSyntaxes, 3);
432
LOG_ERROR(ambitolog, "Unable to add presentation context for " << m_abstractSyntax);
440
LOG_WARN(ambitolog, "Too many PresentationContexts setted");