使用dctmtk实现DICOM文件的发送(StoreSCU)

  1 //=====================================================================
  2 // SendDICOM.cpp : Defines the entry point for the DLL application.
  3 //
  4 //   Created by HGB 2011  Nanjing ChunRen L.T.D 
  5 //=====================================================================
  6 
  7 
  8 #include "stdafx.h"
  9 #include "SendDICOM.h"
 10 #include "osconfig.h" /* make sure OS specific configuration is included first */
 11 
 12 #define INCLUDE_CSTDLIB
 13 #define INCLUDE_CSTDIO
 14 #define INCLUDE_CSTRING
 15 #define INCLUDE_CERRNO
 16 #define INCLUDE_CSTDARG
 17 #define INCLUDE_CCTYPE
 18 #include "ofstdinc.h"
 19 
 20 BEGIN_EXTERN_C
 21 #ifdef HAVE_SYS_FILE_H
 22 #include <sys/file.h>
 23 #endif
 24 END_EXTERN_C
 25 
 26 #ifdef HAVE_GUSI_H
 27 #include <GUSI.h>
 28 #endif
 29 
 30 #include "ofstring.h"
 31 #include "dimse.h"
 32 #include "diutil.h"
 33 #include "dcdatset.h"
 34 #include "dcmetinf.h"
 35 #include "dcfilefo.h"
 36 #include "dcdebug.h"
 37 #include "dcuid.h"
 38 #include "dcdict.h"
 39 #include "dcdeftag.h"
 40 #include "cmdlnarg.h"
 41 #include "ofconapp.h"
 42 #include "dcuid.h"     /* for dcmtk version name */
 43 #include "dicom.h"     /* for DICOM_APPLICATION_REQUESTOR */
 44 #include "dcostrmz.h"  /* for dcmZlibCompressionLevel */
 45 #include "dcasccfg.h"  /* for class DcmAssociationConfiguration */
 46 #include "dcasccff.h"  /* for class DcmAssociationConfigurationFile */
 47 
 48 #ifdef ON_THE_FLY_COMPRESSION
 49 #include "djdecode.h"  /* for dcmjpeg decoders */
 50 #include "djencode.h"  /* for dcmjpeg encoders */
 51 #include "dcrledrg.h"  /* for DcmRLEDecoderRegistration */
 52 #include "dcrleerg.h"  /* for DcmRLEEncoderRegistration */
 53 #endif
 54 
 55 #ifdef WITH_OPENSSL
 56 #include "tlstrans.h"
 57 #include "tlslayer.h"
 58 #endif
 59 
 60 #include "WINSOCK.H"
 61 
 62 #ifdef WITH_ZLIB
 63 #include <zlib.h>          /* for zlibVersion() */
 64 #endif
 65 
 66 static E_TransferSyntax opt_networkTransferSyntax = EXS_Unknown;
 67 static OFBool opt_proposeOnlyRequiredPresentationContexts = OFFalse;
 68 static OFBool opt_combineProposedTransferSyntaxes = OFFalse;
 69 static OFCmdUnsignedInt opt_repeatCount = 1;
 70 static OFBool opt_haltOnUnsuccessfulStore = OFTrue;
 71 static OFCmdUnsignedInt opt_inventPatientCount = 25;
 72 static OFCmdUnsignedInt opt_inventStudyCount = 50;
 73 static OFCmdUnsignedInt opt_inventSeriesCount = 100;
 74 static OFBool opt_inventSOPInstanceInformation = OFFalse;
 75 static OFBool opt_correctUIDPadding = OFFalse;
 76 static OFBool unsuccessfulStoreEncountered = OFFalse;
 77 static OFBool opt_verbose = OFFalse;
 78 static OFBool opt_showPresentationContexts = OFFalse;
 79 static OFBool opt_debug = OFFalse;
 80 static OFBool opt_abortAssociation = OFFalse;
 81 static OFCmdUnsignedInt opt_maxReceivePDULength = ASC_DEFAULTMAXPDU;
 82 static OFCmdUnsignedInt opt_maxSendPDULength = 0;
 83 T_DIMSE_BlockingMode opt_blockMode = DIMSE_BLOCKING;
 84 int opt_dimse_timeout = 0;
 85 int opt_acse_timeout = 30;
 86 static int lastStatusCode = STATUS_Success;
 87 static OFString studyIDPrefix("SID_");   // StudyID is SH (maximum 16 chars)
 88 static OFString accessionNumberPrefix;  // AccessionNumber is SH (maximum 16 chars)
 89 static OFString patientIDPrefix("PID_"); // PatientID is LO (maximum 64 chars)
 90 static OFString patientNamePrefix("OFFIS^TEST_PN_");   // PatientName is PN (maximum 16 chars)
 91 
 92 static OFCondition
 93 addStoragePresentationContexts(T_ASC_Parameters *params, OFList<OFString>& sopClasses);
 94 static OFCondition
 95 cstore(T_ASC_Association * assoc, const OFString& fname);
 96 static OFBool
 97 isaListMember(OFList<OFString>& lst, OFString& s);
 98 
 99 static OFCondition
100 addPresentationContext(T_ASC_Parameters *params,
101     int presentationContextId, const OFString& abstractSyntax,
102     const OFList<OFString>& transferSyntaxList,
103     T_ASC_SC_ROLE proposedRole = ASC_SC_ROLE_DEFAULT);
104 static OFCondition
105 addPresentationContext(T_ASC_Parameters *params,
106     int presentationContextId, const OFString& abstractSyntax,
107     const OFString& transferSyntax,
108     T_ASC_SC_ROLE proposedRole = ASC_SC_ROLE_DEFAULT);
109 static OFCondition
110 storeSCU(T_ASC_Association * assoc, const char *fname);
111 static void
112 replaceSOPInstanceInformation(DcmDataset* dataset);
113 static void
114 progressCallback(void * /*callbackData*/,
115     T_DIMSE_StoreProgress *progress,
116     T_DIMSE_C_StoreRQ * /*req*/);
117 static OFString
118 makeUID(OFString basePrefix, int counter);
119 static int
120 secondsSince1970();
121 static OFString
122 intToString(int i);
123 static OFBool
124 updateStringAttributeValue(DcmItem* dataset, const DcmTagKey& key, OFString& value);
125 
126 BOOL APIENTRY DllMain( HANDLE hModule, 
127                        DWORD  ul_reason_for_call, 
128                        LPVOID lpReserved
129                      )
130 {
131     return TRUE;
132 }
133 
134 int IncInt(int params)
135 {
136     return params+1;
137 }
138 
139 //int IniNet
140 
141 /*==========================================================*/
142 //Created by hgb 20061229
143 //result value:
144 //0: success
145 //-1: not foud file
146 //-2:
147 //-3:
148 //-4:
149 //-5:
150 /*==========================================================*/
151 int __stdcall SendDCM(LPSTR ourTitle, LPSTR peerTitle, 
152                    LPSTR scpIP, LPSTR scpPort, LPSTR FileName)
153 {
154     char sopClassUID[128];
155     char sopInstanceUID[128];
156     OFList<OFString> fileNameList;
157     OFList<OFString> sopClassUIDList;
158     OFList<OFString> sopInstanceUIDList;
159     T_ASC_Network *net;
160     T_ASC_Parameters *params;
161     DIC_NODENAME localHost;
162     DIC_NODENAME peerHost;
163     T_ASC_Association *assoc;
164 
165     //TCHAR tcsModulePath[_MAX_PATH];
166     //::GetModuleFileName(NULL, tcsModulePath, _MAX_PATH);
167 
168     //CString strCurDir = tcsModulePath;
169     //strCurDir = strCurDir.Left(strCurDir.ReverseFind(TEXT('\\'))+1);
170     //char currentFilename[strCurDir.GetLength()+1];
171     //strcpy(currentFilename, strCurDir.GetBuffer());
172     //char *currentFilename = strCurDir;
173     
174 
175 #ifdef HAVE_GUSI_H
176     GUSISetup(GUSIwithSIOUXSockets);
177     GUSISetup(GUSIwithInternetSockets);
178 #endif
179 
180 #ifdef HAVE_WINSOCK_H
181     WSAData winSockData;
182     /* we need at least version 1.1 */
183     WORD winSockVersionNeeded = MAKEWORD( 1, 1 );
184     WSAStartup(winSockVersionNeeded, &winSockData);
185 #endif
186 
187     /*
188     CFileFind find;
189     if(find.FindFile(FileName))
190     {
191         return -1; // not found the file  
192     }
193     */
194 
195 
196     if (access(FileName, R_OK)!=0)
197         return -2; // did't access file
198     if (!DU_findSOPClassAndInstanceInFile(FileName, sopClassUID, sopInstanceUID))
199         return -101;
200     if (!dcmIsaStorageSOPClassUID(sopClassUID))
201         return -102;
202     else
203     {
204         //fileNameList.push_back(FileName);
205         sopClassUIDList.push_back(sopClassUID);
206         sopInstanceUIDList.push_back(sopInstanceUID);
207 
208         OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, 30, &net);
209         if (cond.bad())
210             return -103;
211 
212         cond = ASC_createAssociationParameters(&params, ASC_DEFAULTMAXPDU);
213         if (cond.bad())
214             return -104;
215 
216         ASC_setAPTitles(params, ourTitle, peerTitle, NULL);
217         gethostname(localHost, sizeof(localHost) - 1);
218         sprintf(peerHost, "%s:%s", scpIP, scpPort);////////
219         ASC_setPresentationAddresses(params, localHost, peerHost);
220 
221         cond = addStoragePresentationContexts(params, sopClassUIDList);
222         if (cond.bad())
223         {
224             return -105;
225         }
226 
227         cond = ASC_requestAssociation(net, params, &assoc);
228         if (cond.bad())
229         {
230             if (cond == DUL_ASSOCIATIONREJECTED) {
231                 return -106;
232             } else {  //Association Request Failed
233                 return -107;
234             }
235         }
236 
237         //发送文件
238         cond = EC_Normal;
239         //OFListIterator(OFString) iter = fileNameList.begin();
240         //OFListIterator(OFString) enditer = fileNameList.end();////
241         //cond = cstore(assoc, *iter);  //OFString
242         cond = cstore(assoc, OFString(FileName));
243         if (cond != EC_Normal)
244         {
245             //ASC_releaseAssociation(assoc);
246             //ASC_destroyAssociation(&assoc);
247             //DimseCondition::dump(cond);
248             //#ifdef HAVE_WINSOCK_H
249                 //WSACleanup();
250             //#endif
251             return -108;//send faid;
252         }
253 
254         cond = ASC_releaseAssociation(assoc);
255         if (cond.bad()) 
256             return -109;
257 
258         cond = ASC_destroyAssociation(&assoc);
259         if (cond.bad()) 
260             return -120;
261 
262     }
263 
264 #ifdef HAVE_WINSOCK_H
265     WSACleanup();
266 #endif
267     return 0;
268 
269 }
270 
271 
272 static OFCondition
273 addStoragePresentationContexts(T_ASC_Parameters *params, OFList<OFString>& sopClasses)
274 {
275     /*
276      * Each SOP Class will be proposed in two presentation contexts (unless
277      * the opt_combineProposedTransferSyntaxes global variable is true).
278      * The command line specified a preferred transfer syntax to use.
279      * This prefered transfer syntax will be proposed in one
280      * presentation context and a set of alternative (fallback) transfer
281      * syntaxes will be proposed in a different presentation context.
282      *
283      * Generally, we prefer to use Explicitly encoded transfer syntaxes
284      * and if running on a Little Endian machine we prefer
285      * LittleEndianExplicitTransferSyntax to BigEndianTransferSyntax.
286      * Some SCP implementations will just select the first transfer
287      * syntax they support (this is not part of the standard) so
288      * organise the proposed transfer syntaxes to take advantage
289      * of such behaviour.
290      */
291 
292     // Which transfer syntax was preferred on the command line
293     OFString preferredTransferSyntax;
294     if (opt_networkTransferSyntax == EXS_Unknown) {
295         /* gLocalByteOrder is defined in dcxfer.h */
296         if (gLocalByteOrder == EBO_LittleEndian) {
297             /* we are on a little endian machine */
298             preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;
299         } else {
300             /* we are on a big endian machine */
301             preferredTransferSyntax = UID_BigEndianExplicitTransferSyntax;
302         }
303     } else {
304         DcmXfer xfer(opt_networkTransferSyntax);
305         preferredTransferSyntax = xfer.getXferID();
306     }
307 
308     OFListIterator(OFString) s_cur;
309     OFListIterator(OFString) s_end;
310 
311 
312     OFList<OFString> fallbackSyntaxes;
313     fallbackSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);
314     fallbackSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);
315     fallbackSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);
316     // Remove the preferred syntax from the fallback list
317     fallbackSyntaxes.remove(preferredTransferSyntax);
318     // If little endian implicit is preferred then we don't need any fallback syntaxes
319     // because it is the default transfer syntax and all applications must support it.
320     if (opt_networkTransferSyntax == EXS_LittleEndianImplicit) {
321         fallbackSyntaxes.clear();
322     }
323 
324     // created a list of transfer syntaxes combined from the preferred and fallback syntaxes
325     OFList<OFString> combinedSyntaxes;
326     s_cur = fallbackSyntaxes.begin();
327     s_end = fallbackSyntaxes.end();
328     combinedSyntaxes.push_back(preferredTransferSyntax);
329     while (s_cur != s_end)
330     {
331         if (!isaListMember(combinedSyntaxes, *s_cur)) combinedSyntaxes.push_back(*s_cur);
332         ++s_cur;
333     }
334 
335     if (!opt_proposeOnlyRequiredPresentationContexts) {
336         // add the (short list of) known storage sop classes to the list
337         // the array of Storage SOP Class UIDs comes from dcuid.h
338         for (int i=0; i<numberOfDcmShortSCUStorageSOPClassUIDs; i++) {
339             sopClasses.push_back(dcmShortSCUStorageSOPClassUIDs[i]);
340         }
341     }
342 
343     // thin out the sop classes to remove any duplicates.
344     OFList<OFString> sops;
345     s_cur = sopClasses.begin();
346     s_end = sopClasses.end();
347     while (s_cur != s_end) {
348         if (!isaListMember(sops, *s_cur)) {
349             sops.push_back(*s_cur);
350         }
351         ++s_cur;
352     }
353 
354     // add a presentations context for each sop class / transfer syntax pair
355     OFCondition cond = EC_Normal;
356     int pid = 1; // presentation context id
357     s_cur = sops.begin();
358     s_end = sops.end();
359     while (s_cur != s_end && cond.good()) {
360 
361         if (pid > 255) {
362             ///errmsg("Too many presentation contexts");
363             return ASC_BADPRESENTATIONCONTEXTID;
364         }
365 
366         if (opt_combineProposedTransferSyntaxes) {
367             cond = addPresentationContext(params, pid, *s_cur, combinedSyntaxes);
368             pid += 2;   /* only odd presentation context id's */
369         } else {
370 
371             // sop class with preferred transfer syntax
372             cond = addPresentationContext(params, pid, *s_cur, preferredTransferSyntax);
373             pid += 2;   /* only odd presentation context id's */
374 
375             if (fallbackSyntaxes.size() > 0) {
376                 if (pid > 255) {
377                     //errmsg("Too many presentation contexts");
378                     return ASC_BADPRESENTATIONCONTEXTID;
379                 }
380 
381                 // sop class with fallback transfer syntax
382                 cond = addPresentationContext(params, pid, *s_cur, fallbackSyntaxes);
383                 pid += 2;       /* only odd presentation context id's */
384             }
385         }
386         ++s_cur;
387     }
388 
389     return cond;
390 }
391 
392 static OFCondition
393 cstore(T_ASC_Association * assoc, const OFString& fname)
394     /*
395      * This function will process the given file as often as is specified by opt_repeatCount.
396      * "Process" in this case means "read file, send C-STORE-RQ, receive C-STORE-RSP".
397      *
398      * Parameters:
399      *   assoc - [in] The association (network connection to another DICOM application).
400      *   fname - [in] Name of the file which shall be processed.
401      */
402 {
403     OFCondition cond = EC_Normal;
404 
405     /* opt_repeatCount specifies how many times a certain file shall be processed */
406     int n = (int)opt_repeatCount;
407 
408     /* as long as no error occured and the counter does not equal 0 */
409     while ((cond.good()) && n-- && !(opt_haltOnUnsuccessfulStore && unsuccessfulStoreEncountered))
410     {
411         /* process file (read file, send C-STORE-RQ, receive C-STORE-RSP) */
412         cond = storeSCU(assoc, fname.c_str());
413     }
414 
415     // we don't want to return an error code if --no-halt was specified.
416     if (! opt_haltOnUnsuccessfulStore)
417     {
418         cond = EC_Normal;
419     }
420 
421     /* return result value */
422     return cond;
423 }
424 
425 static OFBool
426 isaListMember(OFList<OFString>& lst, OFString& s)
427 {
428     OFListIterator(OFString) cur = lst.begin();
429     OFListIterator(OFString) end = lst.end();
430 
431     OFBool found = OFFalse;
432 
433     while (cur != end && !found) {
434 
435         found = (s == *cur);
436 
437         ++cur;
438     }
439 
440     return found;
441 }
442 
443 static OFCondition
444 addPresentationContext(T_ASC_Parameters *params,
445     int presentationContextId, const OFString& abstractSyntax,
446     const OFString& transferSyntax,
447     T_ASC_SC_ROLE proposedRole)
448 {
449     const char* c_p = transferSyntax.c_str();
450     OFCondition cond = ASC_addPresentationContext(params, presentationContextId,
451         abstractSyntax.c_str(), &c_p, 1, proposedRole);
452     return cond;
453 }
454 
455 static OFCondition
456 addPresentationContext(T_ASC_Parameters *params,
457     int presentationContextId, const OFString& abstractSyntax,
458     const OFList<OFString>& transferSyntaxList,
459     T_ASC_SC_ROLE proposedRole)
460 {
461     // create an array of supported/possible transfer syntaxes
462     const char** transferSyntaxes = new const char*[transferSyntaxList.size()];
463     int transferSyntaxCount = 0;
464     OFListConstIterator(OFString) s_cur = transferSyntaxList.begin();
465     OFListConstIterator(OFString) s_end = transferSyntaxList.end();
466     while (s_cur != s_end) {
467         transferSyntaxes[transferSyntaxCount++] = (*s_cur).c_str();
468         ++s_cur;
469     }
470 
471     OFCondition cond = ASC_addPresentationContext(params, presentationContextId,
472         abstractSyntax.c_str(), transferSyntaxes, transferSyntaxCount, proposedRole);
473 
474     delete[] transferSyntaxes;
475     return cond;
476 }
477 
478 static OFCondition
479 storeSCU(T_ASC_Association * assoc, const char *fname)
480     /*
481      * This function will read all the information from the given file,
482      * figure out a corresponding presentation context which will be used
483      * to transmit the information over the network to the SCP, and it
484      * will finally initiate the transmission of all data to the SCP.
485      *
486      * Parameters:
487      *   assoc - [in] The association (network connection to another DICOM application).
488      *   fname - [in] Name of the file which shall be processed.
489      */
490 {
491     DIC_US msgId = assoc->nextMsgID++;
492     T_ASC_PresentationContextID presId;
493     T_DIMSE_C_StoreRQ req;
494     T_DIMSE_C_StoreRSP rsp;
495     DIC_UI sopClass;
496     DIC_UI sopInstance;
497     DcmDataset *statusDetail = NULL;
498 
499     unsuccessfulStoreEncountered = OFTrue; // assumption
500 
501     if (opt_verbose) {
502         printf("--------------------------\n");
503         printf("Sending file: %s\n", fname);
504     }
505 
506     /* read information from file. After the call to DcmFileFormat::loadFile(...) the information */
507     /* which is encapsulated in the file will be available through the DcmFileFormat object. */
508     /* In detail, it will be available through calls to DcmFileFormat::getMetaInfo() (for */
509     /* meta header information) and DcmFileFormat::getDataset() (for data set information). */
510     DcmFileFormat dcmff;
511     OFCondition cond = dcmff.loadFile(fname);
512 
513     /* figure out if an error occured while the file was read*/
514     if (cond.bad()) {
515         //errmsg("Bad DICOM file: %s: %s", fname, cond.text());
516         return cond;
517     }
518 
519     /* if required, invent new SOP instance information for the current data set (user option) */
520     if (opt_inventSOPInstanceInformation) {
521         replaceSOPInstanceInformation(dcmff.getDataset());
522     }
523 
524     /* figure out which SOP class and SOP instance is encapsulated in the file */
525     if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(),
526         sopClass, sopInstance, opt_correctUIDPadding)) {
527         //errmsg("No SOP Class & Instance UIDs in file: %s", fname);
528         return DIMSE_BADDATA;
529     }
530 
531     /* figure out which of the accepted presentation contexts should be used */
532     DcmXfer filexfer(dcmff.getDataset()->getOriginalXfer());//??????? added by HGB
533 
534     /* special case: if the file uses an unencapsulated transfer syntax (uncompressed
535      * or deflated explicit VR) and we prefer deflated explicit VR, then try
536      * to find a presentation context for deflated explicit VR first.
537      */
538     if (filexfer.isNotEncapsulated() &&
539         opt_networkTransferSyntax == EXS_DeflatedLittleEndianExplicit)
540     {
541         filexfer = EXS_DeflatedLittleEndianExplicit;
542     }
543 
544     if (filexfer.getXfer() != EXS_Unknown) presId = ASC_findAcceptedPresentationContextID(assoc, sopClass, filexfer.getXferID());
545     else presId = ASC_findAcceptedPresentationContextID(assoc, sopClass);
546     if (presId == 0) {
547         const char *modalityName = dcmSOPClassUIDToModality(sopClass);
548         if (!modalityName) modalityName = dcmFindNameOfUID(sopClass);
549         if (!modalityName) modalityName = "unknown SOP class";
550        // errmsg("No presentation context for: (%s) %s", modalityName, sopClass);
551         return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
552     }
553 
554     /* if required, dump general information concerning transfer syntaxes */
555     if (opt_verbose) {
556         DcmXfer fileTransfer(dcmff.getDataset()->getOriginalXfer());
557         T_ASC_PresentationContext pc;
558         ASC_findAcceptedPresentationContext(assoc->params, presId, &pc);
559         DcmXfer netTransfer(pc.acceptedTransferSyntax);
560         printf("Transfer: %s -> %s\n",
561             dcmFindNameOfUID(fileTransfer.getXferID()), dcmFindNameOfUID(netTransfer.getXferID()));
562     }
563 
564     /* prepare the transmission of data */
565     bzero((char*)&req, sizeof(req));
566     req.MessageID = msgId;
567     strcpy(req.AffectedSOPClassUID, sopClass);
568     strcpy(req.AffectedSOPInstanceUID, sopInstance);
569     req.DataSetType = DIMSE_DATASET_PRESENT;
570     req.Priority = DIMSE_PRIORITY_LOW;
571 
572     /* if required, dump some more general information */
573     if (opt_verbose) {
574         printf("Store SCU RQ: MsgID %d, (%s)\n", msgId, dcmSOPClassUIDToModality(sopClass));
575     }
576 
577     /* finally conduct transmission of data */
578     cond = DIMSE_storeUser(assoc, presId, &req,
579         NULL, dcmff.getDataset(), progressCallback, NULL,
580         opt_blockMode, opt_dimse_timeout,
581         &rsp, &statusDetail, NULL, DU_fileSize(fname));
582 
583     /*
584      * If store command completed normally, with a status
585      * of success or some warning then the image was accepted.
586      */
587     if (cond == EC_Normal && (rsp.DimseStatus == STATUS_Success || DICOM_WARNING_STATUS(rsp.DimseStatus))) {
588         unsuccessfulStoreEncountered = OFFalse;
589     }
590 
591     /* remember the response's status for later transmissions of data */
592     lastStatusCode = rsp.DimseStatus;
593 
594     /* dump some more general information */
595     if (cond == EC_Normal)
596     {
597         if (opt_verbose) {
598             DIMSE_printCStoreRSP(stdout, &rsp);
599         }
600     }
601     else
602     {
603         //errmsg("Store Failed, file: %s:", fname);
604         DimseCondition::dump(cond);
605     }
606 
607     /* dump status detail information if there is some */
608     if (statusDetail != NULL) {
609         printf("  Status Detail:\n");
610         statusDetail->print(COUT);
611         delete statusDetail;
612     }
613     /* return */
614     return cond;
615 }
616 
617 static void
618 replaceSOPInstanceInformation(DcmDataset* dataset)
619 {
620     static OFCmdUnsignedInt patientCounter = 0;
621     static OFCmdUnsignedInt studyCounter = 0;
622     static OFCmdUnsignedInt seriesCounter = 0;
623     static OFCmdUnsignedInt imageCounter = 0;
624     static OFString seriesInstanceUID;
625     static OFString seriesNumber;
626     static OFString studyInstanceUID;
627     static OFString studyID;
628     static OFString accessionNumber;
629     static OFString patientID;
630     static OFString patientName;
631 
632     if (seriesInstanceUID.length() == 0) seriesInstanceUID=makeUID(SITE_SERIES_UID_ROOT, (int)seriesCounter);
633     if (seriesNumber.length() == 0) seriesNumber = intToString((int)seriesCounter);
634     if (studyInstanceUID.length() == 0) studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, (int)studyCounter);
635     if (studyID.length() == 0) studyID = studyIDPrefix + intToString((int)secondsSince1970()) + intToString((int)studyCounter);
636     if (accessionNumber.length() == 0) accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);
637     if (patientID.length() == 0) patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);
638     if (patientName.length() == 0) patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);
639 
640     if (imageCounter >= opt_inventSeriesCount) {
641         imageCounter = 0;
642         seriesCounter++;
643         seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, (int)seriesCounter);
644         seriesNumber = intToString((int)seriesCounter);
645     }
646     if (seriesCounter >= opt_inventStudyCount) {
647         seriesCounter = 0;
648         studyCounter++;
649         studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, (int)studyCounter);
650         studyID = studyIDPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);
651         accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);
652     }
653     if (studyCounter >= opt_inventPatientCount) {
654         // we create as many patients as necessary */
655         studyCounter = 0;
656         patientCounter++;
657         patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);
658         patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);
659     }
660 
661     OFString sopInstanceUID = makeUID(SITE_INSTANCE_UID_ROOT, (int)imageCounter);
662     OFString imageNumber = intToString((int)imageCounter);
663 
664     if (opt_verbose) {
665         COUT << "Inventing Identifying Information (" <<
666             "pa" << patientCounter << ", st" << studyCounter <<
667             ", se" << seriesCounter << ", im" << imageCounter << "): " << endl;
668         COUT << "  PatientName=" << patientName << endl;
669         COUT << "  PatientID=" << patientID << endl;
670         COUT << "  StudyInstanceUID=" << studyInstanceUID << endl;
671         COUT << "  StudyID=" << studyID << endl;
672         COUT << "  SeriesInstanceUID=" << seriesInstanceUID << endl;
673         COUT << "  SeriesNumber=" << seriesNumber << endl;
674         COUT << "  SOPInstanceUID=" << sopInstanceUID << endl;
675         COUT << "  ImageNumber=" << imageNumber << endl;
676     }
677 
678     updateStringAttributeValue(dataset, DCM_PatientsName, patientName);
679     updateStringAttributeValue(dataset, DCM_PatientID, patientID);
680     updateStringAttributeValue(dataset, DCM_StudyInstanceUID, studyInstanceUID);
681     updateStringAttributeValue(dataset, DCM_StudyID, studyID);
682     updateStringAttributeValue(dataset, DCM_SeriesInstanceUID, seriesInstanceUID);
683     updateStringAttributeValue(dataset, DCM_SeriesNumber, seriesNumber);
684     updateStringAttributeValue(dataset, DCM_SOPInstanceUID, sopInstanceUID);
685     updateStringAttributeValue(dataset, DCM_InstanceNumber, imageNumber);
686 
687     imageCounter++;
688 }
689 
690 static void
691 progressCallback(void * /*callbackData*/,
692     T_DIMSE_StoreProgress *progress,
693     T_DIMSE_C_StoreRQ * /*req*/)
694 {
695     if (opt_verbose) {
696         switch (progress->state) {
697         case DIMSE_StoreBegin:
698             printf("XMIT:"); break;
699         case DIMSE_StoreEnd:
700             printf("\n"); break;
701         default:
702             putchar('.'); break;
703         }
704         fflush(stdout);
705     }
706 }
707 
708 static OFString
709 makeUID(OFString basePrefix, int counter)
710 {
711     OFString prefix = basePrefix + "." + intToString(counter);
712     char uidbuf[65];
713     OFString uid = dcmGenerateUniqueIdentifier(uidbuf, prefix.c_str());
714     return uid;
715 }
716 
717 static int
718 secondsSince1970()
719 {
720     time_t t = time(NULL);
721     return (int)t;
722 }
723 
724 static OFString
725 intToString(int i)
726 {
727     char numbuf[32];
728     sprintf(numbuf, "%d", i);
729     return numbuf;
730 }
731 
732 static OFBool
733 updateStringAttributeValue(DcmItem* dataset, const DcmTagKey& key, OFString& value)
734 {
735     DcmStack stack;
736     DcmTag tag(key);
737 
738     OFCondition cond = EC_Normal;
739     cond = dataset->search(key, stack, ESM_fromHere, OFFalse);
740     if (cond != EC_Normal) {
741         CERR << "error: updateStringAttributeValue: cannot find: " << tag.getTagName()
742              << " " << key << ": "
743              << cond.text() << endl;
744         return OFFalse;
745     }
746 
747     DcmElement* elem = (DcmElement*) stack.top();
748 
749     DcmVR vr(elem->ident());
750     if (elem->getLength() > vr.getMaxValueLength()) {
751         CERR << "error: updateStringAttributeValue: INTERNAL ERROR: " << tag.getTagName()
752              << " " << key << ": value too large (max "
753             << vr.getMaxValueLength() << ") for " << vr.getVRName() << " value: " << value << endl;
754         return OFFalse;
755     }
756 
757     cond = elem->putOFStringArray(value);
758     if (cond != EC_Normal) {
759         CERR << "error: updateStringAttributeValue: cannot put string in attribute: " << tag.getTagName()
760              << " " << key << ": "
761              << cond.text() << endl;
762         return OFFalse;
763     }
764 
765     return OFTrue;
766 }

 

posted @ 2012-12-26 10:34  微笑的艾米  阅读(3391)  评论(1编辑  收藏  举报