~ubuntu-branches/ubuntu/wily/ginkgocadx/wily-proposed

« back to all changes in this revision

Viewing changes to src/cadxcore/main/controllers/dcmtk/dicomassociation.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Tille
  • Date: 2011-05-02 08:09:26 UTC
  • Revision ID: james.westby@ubuntu.com-20110502080926-bql5wep49c7hg91t
Tags: upstream-2.4.1.1
Import upstream version 2.4.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 *  $Id: dicomassociation.cpp 3654 2011-04-06 11:00:08Z tovar $
 
4
 *  Ginkgo CADx Project
 
5
 *
 
6
 *  Copyright 2008-10 MetaEmotion S.L. All rights reserved.
 
7
 *  http://ginkgo-cadx.com
 
8
 *
 
9
 *  This file is licensed under LGPL v3 license.
 
10
 *  See License.txt for details
 
11
 *
 
12
 *  Code adapted from Aeskulap
 
13
 *
 
14
 */
 
15
#include <api/icontroladorlog.h>
 
16
#include <main/controllers/controladorlog.h>
 
17
#include "dicomassociation.h"
 
18
#include "dicomnetwork.h"
 
19
 
 
20
#include <stdio.h>
 
21
#include <stdlib.h>
 
22
 
 
23
#ifdef MACRO_QUE_ESTORBA
 
24
#define verify MACRO_QUE_ESTORBA
 
25
#endif
 
26
 
 
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>
 
37
 
 
38
#include <dcmtk/dcmjpeg/djencode.h>
 
39
#include <dcmtk/dcmjpeg/djdecode.h>
 
40
#include <dcmtk/dcmjpeg/djrplol.h>
 
41
#include <dcmtk/dcmjpeg/djrploss.h>
 
42
 
 
43
#ifdef MACRO_QUE_ESTORBA
 
44
#define verify MACRO_QUE_ESTORBA
 
45
#endif
 
46
 
 
47
 
 
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
 
82
};
 
83
 
 
84
const unsigned int Association::AllTransferSyntaxesCount = 19;
 
85
 
 
86
Association::Association(const std::string& _ambitolog) :
 
87
ambitolog(_ambitolog),
 
88
m_pNotificadorProgreso(NULL),
 
89
m_abstractSyntax(NULL),
 
90
m_Stop(false),
 
91
m_calledPort(0),
 
92
m_timeout(15),
 
93
assoc(NULL),
 
94
presId(0),
 
95
msgId(0),
 
96
Net(NULL),
 
97
Role(RT_Requestor),
 
98
AcceptorPort(0),
 
99
m_TLS(false),
 
100
m_UseUserPass(false),
 
101
m_Validate(false)
 
102
{
 
103
    sopClass[0] = 0;
 
104
    sopInstance[0] = 0;
 
105
}
 
106
 
 
107
Association::~Association() {
 
108
    // drop an existing association on shutdown
 
109
    if (assoc != NULL)
 
110
                Drop();
 
111
        assoc = NULL;
 
112
        m_pNotificadorProgreso = NULL;
 
113
}
 
114
 
 
115
CONDITION Association::Drop(CONDITION cond) {
 
116
    // tear down association
 
117
    if (cond == DIMSE_NORMAL) {
 
118
                /* release association */
 
119
                cond = ASC_releaseAssociation(assoc);
 
120
    }
 
121
    else if (cond == DIMSE_PEERREQUESTEDRELEASE) {
 
122
                 cond = ASC_acknowledgeRelease(assoc);
 
123
                 if (SUCCESS(cond)) {
 
124
                        cond = ASC_abortAssociation(assoc);
 
125
                        if (SUCCESS(cond)) {
 
126
                                return cond;
 
127
                        }
 
128
                 }
 
129
    }
 
130
    else if (cond == DIMSE_PEERABORTEDASSOCIATION) {
 
131
                return cond;
 
132
    }
 
133
    else {
 
134
                cond = ASC_abortAssociation(assoc);
 
135
                if (SUCCESS(cond)) {
 
136
                        return cond;
 
137
                }
 
138
    }
 
139
 
 
140
    Destroy();
 
141
    return cond;
 
142
}
 
143
 
 
144
void Association::Destroy() {
 
145
    CONDITION cond = ASC_destroyAssociation(&assoc);
 
146
 
 
147
    Net = NULL;
 
148
    assoc = NULL;
 
149
    msgId = 0;
 
150
    presId = 0;
 
151
    sopClass[0] = 0;
 
152
    sopInstance[0] = 0;
 
153
 
 
154
}
 
155
 
 
156
CONDITION Association::SendObject(DcmDataset *dataset) {
 
157
    CONDITION cond;
 
158
    DcmDataset *statusDetail = NULL;
 
159
 
 
160
         if (Stopped()) {
 
161
                 return DUL_NETWORKCLOSED;
 
162
         }
 
163
 
 
164
    T_DIMSE_C_StoreRQ req;
 
165
    T_DIMSE_C_StoreRSP rsp;
 
166
 
 
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;
 
171
    }
 
172
 
 
173
    /* which presentation context should be used */
 
174
    presId = ASC_findAcceptedPresentationContextID(assoc, sopClass);
 
175
    if (presId == 0) {
 
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;
 
181
    }
 
182
 
 
183
    // init store
 
184
 
 
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;
 
191
 
 
192
    // convert to accepted transfer syntax
 
193
    T_ASC_PresentationContext pc;
 
194
    cond = ASC_findAcceptedPresentationContext(assoc->params, presId, &pc);
 
195
    ASC_dumpPresentationContext(&pc, COUT);
 
196
 
 
197
    DJEncoderRegistration::registerCodecs(
 
198
                ECC_lossyYCbCr,
 
199
                EUC_never, // UID generation (never create new UID's)
 
200
                OFFalse, // verbose
 
201
                OFTrue); // optimize huffman table
 
202
 
 
203
    DcmXfer opt_oxferSyn(pc.acceptedTransferSyntax);
 
204
    E_TransferSyntax ori_oxferSyn = dataset->getOriginalXfer();
 
205
 
 
206
    DcmXfer original_xfer(dataset->getOriginalXfer());
 
207
 
 
208
    if (opt_oxferSyn.getXfer() != ori_oxferSyn) {
 
209
                LOG_DEBUG(ambitolog, "Convirtiendo objeto a Transfer-Syntax aceptado: " << opt_oxferSyn.getXferName());
 
210
 
 
211
                CONDITION cond;
 
212
                // create RepresentationParameter
 
213
                DJ_RPLossless rp_lossless(6, 0);
 
214
                DJ_RPLossy rp_lossy(70);
 
215
 
 
216
                // NEW
 
217
 
 
218
                const DcmRepresentationParameter *rp = NULL;
 
219
 
 
220
                if (opt_oxferSyn.getXfer() == EXS_JPEGProcess14SV1TransferSyntax || opt_oxferSyn.getXfer() == EXS_JPEGProcess14TransferSyntax) {
 
221
                        rp = &rp_lossless;
 
222
                }
 
223
                else if (opt_oxferSyn.getXfer() == EXS_JPEGProcess1TransferSyntax || opt_oxferSyn.getXfer() == EXS_JPEGProcess2_4TransferSyntax) {
 
224
                        rp = &rp_lossy;
 
225
                }
 
226
 
 
227
                // recompress ?
 
228
                if (rp != NULL) {
 
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");                                }
 
233
                        }
 
234
                }
 
235
 
 
236
                cond = dataset->chooseRepresentation(opt_oxferSyn.getXfer(), rp);
 
237
                if (cond.bad()) {
 
238
                        LOG_ERROR(ambitolog, "Error al elegir la representación: " << cond.text());
 
239
                }
 
240
 
 
241
                if (dataset->canWriteXfer(opt_oxferSyn.getXfer())) {
 
242
                        LOG_DEBUG(ambitolog, "El Transfer Syntax de salida (" <<  opt_oxferSyn.getXferName() << " puede ser escrito");
 
243
                }
 
244
                else {
 
245
                        LOG_ERROR(ambitolog, "No se encontró ninguna conversión posible al El Transfer Syntax de salida (" <<  opt_oxferSyn.getXferName());
 
246
                }
 
247
    }
 
248
 
 
249
    // store it
 
250
 
 
251
    cond = DIMSE_storeUser(
 
252
                                                   assoc,
 
253
                                                   presId,
 
254
                                                   &req,
 
255
                                                   NULL,
 
256
                                                   dataset,
 
257
                                                   NULL,
 
258
                                                   NULL,
 
259
                                                   (m_timeout == 0) ? DIMSE_BLOCKING : DIMSE_NONBLOCKING,
 
260
                                                   m_timeout,
 
261
                                                   &rsp,
 
262
                                                   &statusDetail);
 
263
 
 
264
    // increase message id
 
265
    msgId++;
 
266
 
 
267
    // what happened
 
268
 
 
269
    if (rsp.DataSetType == DIMSE_DATASET_PRESENT) {
 
270
                LOG_DEBUG(ambitolog, "Respuesta con dataset");
 
271
    }
 
272
 
 
273
    if (statusDetail != NULL) {
 
274
                LOG_TRACE(ambitolog, "Estado: " << DumpDataset(statusDetail));
 
275
                delete statusDetail;
 
276
    }
 
277
 
 
278
    if (cond != DIMSE_NORMAL) {
 
279
                return cond;
 
280
    }
 
281
 
 
282
        if (rsp.DimseStatus == STATUS_Success) {
 
283
                return DIMSE_NORMAL;
 
284
        }
 
285
        else {
 
286
                LOG_ERROR(ambitolog, "DIMSE Status fallido: " << rsp.DimseStatus);
 
287
                return DIMSE_BADDATA;
 
288
        }
 
289
}
 
290
 
 
291
CONDITION Association::SendObject(DcmFileFormat *dcmff) {
 
292
        if (Stopped()) {
 
293
                return DUL_NETWORKCLOSED;
 
294
        }
 
295
   DcmDataset* dataset = dcmff->getDataset();
 
296
   return SendObject(dataset);
 
297
}
 
298
 
 
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
 
301
    assoc = NULL;
 
302
 
 
303
    // fill in parameters
 
304
    if (abstractSyntax != NULL) {
 
305
                m_abstractSyntax = (char*) abstractSyntax;
 
306
    }
 
307
 
 
308
    m_calledAET = title;
 
309
    m_calledPeer = peer;
 
310
    m_calledPort = port;
 
311
 
 
312
    m_ourAET = ouraet;
 
313
 
 
314
    msgId = 0;
 
315
    presId = 0;
 
316
}
 
317
 
 
318
bool Association::SendEchoRequest() {
 
319
    DIC_US status;
 
320
    DcmDataset *statusDetail = NULL;
 
321
 
 
322
         if (Stopped()) {
 
323
                 return false;
 
324
         }
 
325
 
 
326
    OFCondition cond = DIMSE_echoUser(assoc, ++msgId, DIMSE_BLOCKING, 0, &status, &statusDetail);
 
327
    if (cond.good()) {
 
328
                LOG_DEBUG(ambitolog, "DIMSE ECO Completado. Estado: " << DU_cstoreStatusString(status));
 
329
    }
 
330
    else {
 
331
                LOG_ERROR(ambitolog, "DIMSE ECO Fallido: " << cond.text());
 
332
    }
 
333
 
 
334
    if (statusDetail != NULL) {
 
335
                delete statusDetail;
 
336
    }
 
337
 
 
338
    return cond.good();
 
339
}
 
340
 
 
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);
 
345
#else
 
346
    snprintf(temp, 16, "%i", value);
 
347
#endif
 
348
    return AddKey(query, tag, temp);
 
349
}
 
350
 
 
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);
 
355
#else
 
356
    snprintf(temp, 16, format, value);
 
357
#endif
 
358
    return AddKey(query, tag, temp);
 
359
}
 
360
 
 
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);
 
365
#else
 
366
    snprintf(temp, 16, "%i", value);
 
367
#endif
 
368
    return AddKey(query, tag, temp);
 
369
}
 
370
 
 
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);
 
375
#else
 
376
    snprintf(temp, 16, format, value);
 
377
#endif
 
378
    return AddKey(query, tag, temp);
 
379
}
 
380
 
 
381
bool Association::AddKey(DcmDataset *query, const DcmTagKey& t, const char* value) {
 
382
    return AddCustomKey/*< DcmDataset >*/(query, t, value);
 
383
}
 
384
 
 
385
bool Association::AddKey(DcmItem *query, const DcmTagKey& t, const char* value) {
 
386
    return AddCustomKey/*< DcmItem >*/(query, t, value);
 
387
}
 
388
 
 
389
bool Association::AddQueryLevel(DcmDataset *query, const std::string& level) {
 
390
    return AddKey(query, DCM_QueryRetrieveLevel, level.c_str());
 
391
}
 
392
 
 
393
GIL::DICOM::DCMTK::Network* Association::GetNetwork() {
 
394
    return Net;
 
395
}
 
396
 
 
397
CONDITION Association::Connect(GIL::DICOM::DCMTK::Network *network, int pdu) {
 
398
    Net = network;
 
399
    return network->ConnectAssociation(this, pdu);
 
400
}
 
401
 
 
402
const std::string& Association::GetOurAET() {
 
403
    return m_ourAET;
 
404
}
 
405
 
 
406
const char* Association::GetKey(DcmDataset* query, const DcmTagKey& tag) {
 
407
    OFString val;
 
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));
 
412
#else
 
413
    strncpy(buffer, val.c_str(), sizeof (buffer));
 
414
#endif
 
415
 
 
416
    return buffer;
 
417
}
 
418
 
 
419
void Association::SetTimeout(int t) {
 
420
    m_timeout = t;
 
421
}
 
422
 
 
423
int Association::GetTimeout() {
 
424
    return m_timeout;
 
425
}
 
426
 
 
427
CONDITION Association::addAllStoragePresentationContexts(T_ASC_Parameters *params, bool /*bProposeCompression*/, int /*lossy*/) {
 
428
    unsigned int pid = 1;
 
429
 
 
430
        CONDITION cond = ASC_addPresentationContext(params, pid, m_abstractSyntax, AllTransferSyntaxes, 3);
 
431
        if (cond.bad()) {
 
432
                LOG_ERROR(ambitolog, "Unable to add presentation context for " << m_abstractSyntax);
 
433
                return cond;
 
434
        }
 
435
 
 
436
 
 
437
        pid += 2;
 
438
 
 
439
        if (pid >= 255) {
 
440
                LOG_WARN(ambitolog, "Too many PresentationContexts setted");
 
441
        }
 
442
 
 
443
    return cond;
 
444
}