您的位置:首页 > 其它

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

2011-08-28 23:05 253 查看
//=====================================================================

// SendDICOM.cpp : Defines the entry point for the DLL application.

//

// Created by HGB 2011 Nanjing ChunRen L.T.D

//=====================================================================

#include "stdafx.h"

#include "SendDICOM.h"

#include "osconfig.h" /* make sure OS specific configuration is included first */

#define INCLUDE_CSTDLIB

#define INCLUDE_CSTDIO

#define INCLUDE_CSTRING

#define INCLUDE_CERRNO

#define INCLUDE_CSTDARG

#define INCLUDE_CCTYPE

#include "ofstdinc.h"

BEGIN_EXTERN_C

#ifdef HAVE_SYS_FILE_H

#include <sys/file.h>

#endif

END_EXTERN_C

#ifdef HAVE_GUSI_H

#include <GUSI.h>

#endif

#include "ofstring.h"

#include "dimse.h"

#include "diutil.h"

#include "dcdatset.h"

#include "dcmetinf.h"

#include "dcfilefo.h"

#include "dcdebug.h"

#include "dcuid.h"

#include "dcdict.h"

#include "dcdeftag.h"

#include "cmdlnarg.h"

#include "ofconapp.h"

#include "dcuid.h" /* for dcmtk version name */

#include "dicom.h" /* for DICOM_APPLICATION_REQUESTOR */

#include "dcostrmz.h" /* for dcmZlibCompressionLevel */

#include "dcasccfg.h" /* for class DcmAssociationConfiguration */

#include "dcasccff.h" /* for class DcmAssociationConfigurationFile */

#ifdef ON_THE_FLY_COMPRESSION

#include "djdecode.h" /* for dcmjpeg decoders */

#include "djencode.h" /* for dcmjpeg encoders */

#include "dcrledrg.h" /* for DcmRLEDecoderRegistration */

#include "dcrleerg.h" /* for DcmRLEEncoderRegistration */

#endif

#ifdef WITH_OPENSSL

#include "tlstrans.h"

#include "tlslayer.h"

#endif

#include "WINSOCK.H"

#ifdef WITH_ZLIB

#include <zlib.h> /* for zlibVersion() */

#endif

static E_TransferSyntax opt_networkTransferSyntax = EXS_Unknown;

static OFBool opt_proposeOnlyRequiredPresentationContexts = OFFalse;

static OFBool opt_combineProposedTransferSyntaxes = OFFalse;

static OFCmdUnsignedInt opt_repeatCount = 1;

static OFBool opt_haltOnUnsuccessfulStore = OFTrue;

static OFCmdUnsignedInt opt_inventPatientCount = 25;

static OFCmdUnsignedInt opt_inventStudyCount = 50;

static OFCmdUnsignedInt opt_inventSeriesCount = 100;

static OFBool opt_inventSOPInstanceInformation = OFFalse;

static OFBool opt_correctUIDPadding = OFFalse;

static OFBool unsuccessfulStoreEncountered = OFFalse;

static OFBool opt_verbose = OFFalse;

static OFBool opt_showPresentationContexts = OFFalse;

static OFBool opt_debug = OFFalse;

static OFBool opt_abortAssociation = OFFalse;

static OFCmdUnsignedInt opt_maxReceivePDULength = ASC_DEFAULTMAXPDU;

static OFCmdUnsignedInt opt_maxSendPDULength = 0;

T_DIMSE_BlockingMode opt_blockMode = DIMSE_BLOCKING;

int opt_dimse_timeout = 0;

int opt_acse_timeout = 30;

static int lastStatusCode = STATUS_Success;

static OFString studyIDPrefix("SID_"); // StudyID is SH (maximum 16 chars)

static OFString accessionNumberPrefix; // AccessionNumber is SH (maximum 16 chars)

static OFString patientIDPrefix("PID_"); // PatientID is LO (maximum 64 chars)

static OFString patientNamePrefix("OFFIS^TEST_PN_"); // PatientName is PN (maximum 16 chars)

static OFCondition

addStoragePresentationContexts(T_ASC_Parameters *params, OFList<OFString>& sopClasses);

static OFCondition

cstore(T_ASC_Association * assoc, const OFString& fname);

static OFBool

isaListMember(OFList<OFString>& lst, OFString& s);

static OFCondition

addPresentationContext(T_ASC_Parameters *params,

int presentationContextId, const OFString& abstractSyntax,

const OFList<OFString>& transferSyntaxList,

T_ASC_SC_ROLE proposedRole = ASC_SC_ROLE_DEFAULT);

static OFCondition

addPresentationContext(T_ASC_Parameters *params,

int presentationContextId, const OFString& abstractSyntax,

const OFString& transferSyntax,

T_ASC_SC_ROLE proposedRole = ASC_SC_ROLE_DEFAULT);

static OFCondition

storeSCU(T_ASC_Association * assoc, const char *fname);

static void

replaceSOPInstanceInformation(DcmDataset* dataset);

static void

progressCallback(void * /*callbackData*/,

T_DIMSE_StoreProgress *progress,

T_DIMSE_C_StoreRQ * /*req*/);

static OFString

makeUID(OFString basePrefix, int counter);

static int

secondsSince1970();

static OFString

intToString(int i);

static OFBool

updateStringAttributeValue(DcmItem* dataset, const DcmTagKey& key, OFString& value);

BOOL APIENTRY DllMain( HANDLE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

return TRUE;

}

int IncInt(int params)

{

return params+1;

}

//int IniNet

/*==========================================================*/

//Created by hgb 20061229

//result value:

//0: success

//-1: not foud file

//-2:

//-3:

//-4:

//-5:

/*==========================================================*/

int __stdcall SendDCM(LPSTR ourTitle, LPSTR peerTitle,

LPSTR scpIP, LPSTR scpPort, LPSTR FileName)

{

char sopClassUID[128];

char sopInstanceUID[128];

OFList<OFString> fileNameList;

OFList<OFString> sopClassUIDList;

OFList<OFString> sopInstanceUIDList;

T_ASC_Network *net;

T_ASC_Parameters *params;

DIC_NODENAME localHost;

DIC_NODENAME peerHost;

T_ASC_Association *assoc;

//TCHAR tcsModulePath[_MAX_PATH];

//::GetModuleFileName(NULL, tcsModulePath, _MAX_PATH);

//CString strCurDir = tcsModulePath;

//strCurDir = strCurDir.Left(strCurDir.ReverseFind(TEXT('\\'))+1);

//char currentFilename[strCurDir.GetLength()+1];

//strcpy(currentFilename, strCurDir.GetBuffer());

//char *currentFilename = strCurDir;

#ifdef HAVE_GUSI_H

GUSISetup(GUSIwithSIOUXSockets);

GUSISetup(GUSIwithInternetSockets);

#endif

#ifdef HAVE_WINSOCK_H

WSAData winSockData;

/* we need at least version 1.1 */

WORD winSockVersionNeeded = MAKEWORD( 1, 1 );

WSAStartup(winSockVersionNeeded, &winSockData);

#endif

/*

CFileFind find;

if(find.FindFile(FileName))

{

return -1; // not found the file

}

*/

if (access(FileName, R_OK)!=0)

return -2; // did't access file

if (!DU_findSOPClassAndInstanceInFile(FileName, sopClassUID, sopInstanceUID))

return -101;

if (!dcmIsaStorageSOPClassUID(sopClassUID))

return -102;

else

{

//fileNameList.push_back(FileName);

sopClassUIDList.push_back(sopClassUID);

sopInstanceUIDList.push_back(sopInstanceUID);

OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, 30, &net);

if (cond.bad())

return -103;

cond = ASC_createAssociationParameters(¶ms, ASC_DEFAULTMAXPDU);

if (cond.bad())

return -104;

ASC_setAPTitles(params, ourTitle, peerTitle, NULL);

gethostname(localHost, sizeof(localHost) - 1);

sprintf(peerHost, "%s:%s", scpIP, scpPort);////////

ASC_setPresentationAddresses(params, localHost, peerHost);

cond = addStoragePresentationContexts(params, sopClassUIDList);

if (cond.bad())

{

return -105;

}

cond = ASC_requestAssociation(net, params, &assoc);

if (cond.bad())

{

if (cond == DUL_ASSOCIATIONREJECTED) {

return -106;

} else { //Association Request Failed

return -107;

}

}

//发送文件

cond = EC_Normal;

//OFListIterator(OFString) iter = fileNameList.begin();

//OFListIterator(OFString) enditer = fileNameList.end();////

//cond = cstore(assoc, *iter); //OFString

cond = cstore(assoc, OFString(FileName));

if (cond != EC_Normal)

{

//ASC_releaseAssociation(assoc);

//ASC_destroyAssociation(&assoc);

//DimseCondition::dump(cond);

//#ifdef HAVE_WINSOCK_H

//WSACleanup();

//#endif

return -108;//send faid;

}

cond = ASC_releaseAssociation(assoc);

if (cond.bad())

return -109;

cond = ASC_destroyAssociation(&assoc);

if (cond.bad())

return -120;

}

#ifdef HAVE_WINSOCK_H

WSACleanup();

#endif

return 0;

}

static OFCondition

addStoragePresentationContexts(T_ASC_Parameters *params, OFList<OFString>& sopClasses)

{

/*

* Each SOP Class will be proposed in two presentation contexts (unless

* the opt_combineProposedTransferSyntaxes global variable is true).

* The command line specified a preferred transfer syntax to use.

* This prefered transfer syntax will be proposed in one

* presentation context and a set of alternative (fallback) transfer

* syntaxes will be proposed in a different presentation context.

*

* Generally, we prefer to use Explicitly encoded transfer syntaxes

* and if running on a Little Endian machine we prefer

* LittleEndianExplicitTransferSyntax to BigEndianTransferSyntax.

* Some SCP implementations will just select the first transfer

* syntax they support (this is not part of the standard) so

* organise the proposed transfer syntaxes to take advantage

* of such behaviour.

*/

// Which transfer syntax was preferred on the command line

OFString preferredTransferSyntax;

if (opt_networkTransferSyntax == EXS_Unknown) {

/* gLocalByteOrder is defined in dcxfer.h */

if (gLocalByteOrder == EBO_LittleEndian) {

/* we are on a little endian machine */

preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;

} else {

/* we are on a big endian machine */

preferredTransferSyntax = UID_BigEndianExplicitTransferSyntax;

}

} else {

DcmXfer xfer(opt_networkTransferSyntax);

preferredTransferSyntax = xfer.getXferID();

}

OFListIterator(OFString) s_cur;

OFListIterator(OFString) s_end;

OFList<OFString> fallbackSyntaxes;

fallbackSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);

fallbackSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);

fallbackSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);

// Remove the preferred syntax from the fallback list

fallbackSyntaxes.remove(preferredTransferSyntax);

// If little endian implicit is preferred then we don't need any fallback syntaxes

// because it is the default transfer syntax and all applications must support it.

if (opt_networkTransferSyntax == EXS_LittleEndianImplicit) {

fallbackSyntaxes.clear();

}

// created a list of transfer syntaxes combined from the preferred and fallback syntaxes

OFList<OFString> combinedSyntaxes;

s_cur = fallbackSyntaxes.begin();

s_end = fallbackSyntaxes.end();

combinedSyntaxes.push_back(preferredTransferSyntax);

while (s_cur != s_end)

{

if (!isaListMember(combinedSyntaxes, *s_cur)) combinedSyntaxes.push_back(*s_cur);

++s_cur;

}

if (!opt_proposeOnlyRequiredPresentationContexts) {

// add the (short list of) known storage sop classes to the list

// the array of Storage SOP Class UIDs comes from dcuid.h

for (int i=0; i<numberOfDcmShortSCUStorageSOPClassUIDs; i++) {

sopClasses.push_back(dcmShortSCUStorageSOPClassUIDs[i]);

}

}

// thin out the sop classes to remove any duplicates.

OFList<OFString> sops;

s_cur = sopClasses.begin();

s_end = sopClasses.end();

while (s_cur != s_end) {

if (!isaListMember(sops, *s_cur)) {

sops.push_back(*s_cur);

}

++s_cur;

}

// add a presentations context for each sop class / transfer syntax pair

OFCondition cond = EC_Normal;

int pid = 1; // presentation context id

s_cur = sops.begin();

s_end = sops.end();

while (s_cur != s_end && cond.good()) {

if (pid > 255) {

///errmsg("Too many presentation contexts");

return ASC_BADPRESENTATIONCONTEXTID;

}

if (opt_combineProposedTransferSyntaxes) {

cond = addPresentationContext(params, pid, *s_cur, combinedSyntaxes);

pid += 2; /* only odd presentation context id's */

} else {

// sop class with preferred transfer syntax

cond = addPresentationContext(params, pid, *s_cur, preferredTransferSyntax);

pid += 2; /* only odd presentation context id's */

if (fallbackSyntaxes.size() > 0) {

if (pid > 255) {

//errmsg("Too many presentation contexts");

return ASC_BADPRESENTATIONCONTEXTID;

}

// sop class with fallback transfer syntax

cond = addPresentationContext(params, pid, *s_cur, fallbackSyntaxes);

pid += 2; /* only odd presentation context id's */

}

}

++s_cur;

}

return cond;

}

static OFCondition

cstore(T_ASC_Association * assoc, const OFString& fname)

/*

* This function will process the given file as often as is specified by opt_repeatCount.

* "Process" in this case means "read file, send C-STORE-RQ, receive C-STORE-RSP".

*

* Parameters:

* assoc - [in] The association (network connection to another DICOM application).

* fname - [in] Name of the file which shall be processed.

*/

{

OFCondition cond = EC_Normal;

/* opt_repeatCount specifies how many times a certain file shall be processed */

int n = (int)opt_repeatCount;

/* as long as no error occured and the counter does not equal 0 */

while ((cond.good()) && n-- && !(opt_haltOnUnsuccessfulStore && unsuccessfulStoreEncountered))

{

/* process file (read file, send C-STORE-RQ, receive C-STORE-RSP) */

cond = storeSCU(assoc, fname.c_str());

}

// we don't want to return an error code if --no-halt was specified.

if (! opt_haltOnUnsuccessfulStore)

{

cond = EC_Normal;

}

/* return result value */

return cond;

}

static OFBool

isaListMember(OFList<OFString>& lst, OFString& s)

{

OFListIterator(OFString) cur = lst.begin();

OFListIterator(OFString) end = lst.end();

OFBool found = OFFalse;

while (cur != end && !found) {

found = (s == *cur);

++cur;

}

return found;

}

static OFCondition

addPresentationContext(T_ASC_Parameters *params,

int presentationContextId, const OFString& abstractSyntax,

const OFString& transferSyntax,

T_ASC_SC_ROLE proposedRole)

{

const char* c_p = transferSyntax.c_str();

OFCondition cond = ASC_addPresentationContext(params, presentationContextId,

abstractSyntax.c_str(), &c_p, 1, proposedRole);

return cond;

}

static OFCondition

addPresentationContext(T_ASC_Parameters *params,

int presentationContextId, const OFString& abstractSyntax,

const OFList<OFString>& transferSyntaxList,

T_ASC_SC_ROLE proposedRole)

{

// create an array of supported/possible transfer syntaxes

const char** transferSyntaxes = new const char*[transferSyntaxList.size()];

int transferSyntaxCount = 0;

OFListConstIterator(OFString) s_cur = transferSyntaxList.begin();

OFListConstIterator(OFString) s_end = transferSyntaxList.end();

while (s_cur != s_end) {

transferSyntaxes[transferSyntaxCount++] = (*s_cur).c_str();

++s_cur;

}

OFCondition cond = ASC_addPresentationContext(params, presentationContextId,

abstractSyntax.c_str(), transferSyntaxes, transferSyntaxCount, proposedRole);

delete[] transferSyntaxes;

return cond;

}

static OFCondition

storeSCU(T_ASC_Association * assoc, const char *fname)

/*

* This function will read all the information from the given file,

* figure out a corresponding presentation context which will be used

* to transmit the information over the network to the SCP, and it

* will finally initiate the transmission of all data to the SCP.

*

* Parameters:

* assoc - [in] The association (network connection to another DICOM application).

* fname - [in] Name of the file which shall be processed.

*/

{

DIC_US msgId = assoc->nextMsgID++;

T_ASC_PresentationContextID presId;

T_DIMSE_C_StoreRQ req;

T_DIMSE_C_StoreRSP rsp;

DIC_UI sopClass;

DIC_UI sopInstance;

DcmDataset *statusDetail = NULL;

unsuccessfulStoreEncountered = OFTrue; // assumption

if (opt_verbose) {

printf("--------------------------\n");

printf("Sending file: %s\n", fname);

}

/* read information from file. After the call to DcmFileFormat::loadFile(...) the information */

/* which is encapsulated in the file will be available through the DcmFileFormat object. */

/* In detail, it will be available through calls to DcmFileFormat::getMetaInfo() (for */

/* meta header information) and DcmFileFormat::getDataset() (for data set information). */

DcmFileFormat dcmff;

OFCondition cond = dcmff.loadFile(fname);

/* figure out if an error occured while the file was read*/

if (cond.bad()) {

//errmsg("Bad DICOM file: %s: %s", fname, cond.text());

return cond;

}

/* if required, invent new SOP instance information for the current data set (user option) */

if (opt_inventSOPInstanceInformation) {

replaceSOPInstanceInformation(dcmff.getDataset());

}

/* figure out which SOP class and SOP instance is encapsulated in the file */

if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(),

sopClass, sopInstance, opt_correctUIDPadding)) {

//errmsg("No SOP Class & Instance UIDs in file: %s", fname);

return DIMSE_BADDATA;

}

/* figure out which of the accepted presentation contexts should be used */

DcmXfer filexfer(dcmff.getDataset()->getOriginalXfer());//??????? added by HGB

/* special case: if the file uses an unencapsulated transfer syntax (uncompressed

* or deflated explicit VR) and we prefer deflated explicit VR, then try

* to find a presentation context for deflated explicit VR first.

*/

if (filexfer.isNotEncapsulated() &&

opt_networkTransferSyntax == EXS_DeflatedLittleEndianExplicit)

{

filexfer = EXS_DeflatedLittleEndianExplicit;

}

if (filexfer.getXfer() != EXS_Unknown) presId = ASC_findAcceptedPresentationContextID(assoc, sopClass, filexfer.getXferID());

else presId = ASC_findAcceptedPresentationContextID(assoc, sopClass);

if (presId == 0) {

const char *modalityName = dcmSOPClassUIDToModality(sopClass);

if (!modalityName) modalityName = dcmFindNameOfUID(sopClass);

if (!modalityName) modalityName = "unknown SOP class";

// errmsg("No presentation context for: (%s) %s", modalityName, sopClass);

return DIMSE_NOVALIDPRESENTATIONCONTEXTID;

}

/* if required, dump general information concerning transfer syntaxes */

if (opt_verbose) {

DcmXfer fileTransfer(dcmff.getDataset()->getOriginalXfer());

T_ASC_PresentationContext pc;

ASC_findAcceptedPresentationContext(assoc->params, presId, &pc);

DcmXfer netTransfer(pc.acceptedTransferSyntax);

printf("Transfer: %s -> %s\n",

dcmFindNameOfUID(fileTransfer.getXferID()), dcmFindNameOfUID(netTransfer.getXferID()));

}

/* prepare the transmission of data */

bzero((char*)&req, sizeof(req));

req.MessageID = msgId;

strcpy(req.AffectedSOPClassUID, sopClass);

strcpy(req.AffectedSOPInstanceUID, sopInstance);

req.DataSetType = DIMSE_DATASET_PRESENT;

req.Priority = DIMSE_PRIORITY_LOW;

/* if required, dump some more general information */

if (opt_verbose) {

printf("Store SCU RQ: MsgID %d, (%s)\n", msgId, dcmSOPClassUIDToModality(sopClass));

}

/* finally conduct transmission of data */

cond = DIMSE_storeUser(assoc, presId, &req,

NULL, dcmff.getDataset(), progressCallback, NULL,

opt_blockMode, opt_dimse_timeout,

&rsp, &statusDetail, NULL, DU_fileSize(fname));

/*

* If store command completed normally, with a status

* of success or some warning then the image was accepted.

*/

if (cond == EC_Normal && (rsp.DimseStatus == STATUS_Success || DICOM_WARNING_STATUS(rsp.DimseStatus))) {

unsuccessfulStoreEncountered = OFFalse;

}

/* remember the response's status for later transmissions of data */

lastStatusCode = rsp.DimseStatus;

/* dump some more general information */

if (cond == EC_Normal)

{

if (opt_verbose) {

DIMSE_printCStoreRSP(stdout, &rsp);

}

}

else

{

//errmsg("Store Failed, file: %s:", fname);

DimseCondition::dump(cond);

}

/* dump status detail information if there is some */

if (statusDetail != NULL) {

printf(" Status Detail:\n");

statusDetail->print(COUT);

delete statusDetail;

}

/* return */

return cond;

}

static void

replaceSOPInstanceInformation(DcmDataset* dataset)

{

static OFCmdUnsignedInt patientCounter = 0;

static OFCmdUnsignedInt studyCounter = 0;

static OFCmdUnsignedInt seriesCounter = 0;

static OFCmdUnsignedInt imageCounter = 0;

static OFString seriesInstanceUID;

static OFString seriesNumber;

static OFString studyInstanceUID;

static OFString studyID;

static OFString accessionNumber;

static OFString patientID;

static OFString patientName;

if (seriesInstanceUID.length() == 0) seriesInstanceUID=makeUID(SITE_SERIES_UID_ROOT, (int)seriesCounter);

if (seriesNumber.length() == 0) seriesNumber = intToString((int)seriesCounter);

if (studyInstanceUID.length() == 0) studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, (int)studyCounter);

if (studyID.length() == 0) studyID = studyIDPrefix + intToString((int)secondsSince1970()) + intToString((int)studyCounter);

if (accessionNumber.length() == 0) accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);

if (patientID.length() == 0) patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);

if (patientName.length() == 0) patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);

if (imageCounter >= opt_inventSeriesCount) {

imageCounter = 0;

seriesCounter++;

seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, (int)seriesCounter);

seriesNumber = intToString((int)seriesCounter);

}

if (seriesCounter >= opt_inventStudyCount) {

seriesCounter = 0;

studyCounter++;

studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, (int)studyCounter);

studyID = studyIDPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);

accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);

}

if (studyCounter >= opt_inventPatientCount) {

// we create as many patients as necessary */

studyCounter = 0;

patientCounter++;

patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);

patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);

}

OFString sopInstanceUID = makeUID(SITE_INSTANCE_UID_ROOT, (int)imageCounter);

OFString imageNumber = intToString((int)imageCounter);

if (opt_verbose) {

COUT << "Inventing Identifying Information (" <<

"pa" << patientCounter << ", st" << studyCounter <<

", se" << seriesCounter << ", im" << imageCounter << "): " << endl;

COUT << " PatientName=" << patientName << endl;

COUT << " PatientID=" << patientID << endl;

COUT << " StudyInstanceUID=" << studyInstanceUID << endl;

COUT << " StudyID=" << studyID << endl;

COUT << " SeriesInstanceUID=" << seriesInstanceUID << endl;

COUT << " SeriesNumber=" << seriesNumber << endl;

COUT << " SOPInstanceUID=" << sopInstanceUID << endl;

COUT << " ImageNumber=" << imageNumber << endl;

}

updateStringAttributeValue(dataset, DCM_PatientsName, patientName);

updateStringAttributeValue(dataset, DCM_PatientID, patientID);

updateStringAttributeValue(dataset, DCM_StudyInstanceUID, studyInstanceUID);

updateStringAttributeValue(dataset, DCM_StudyID, studyID);

updateStringAttributeValue(dataset, DCM_SeriesInstanceUID, seriesInstanceUID);

updateStringAttributeValue(dataset, DCM_SeriesNumber, seriesNumber);

updateStringAttributeValue(dataset, DCM_SOPInstanceUID, sopInstanceUID);

updateStringAttributeValue(dataset, DCM_InstanceNumber, imageNumber);

imageCounter++;

}

static void

progressCallback(void * /*callbackData*/,

T_DIMSE_StoreProgress *progress,

T_DIMSE_C_StoreRQ * /*req*/)

{

if (opt_verbose) {

switch (progress->state) {

case DIMSE_StoreBegin:

printf("XMIT:"); break;

case DIMSE_StoreEnd:

printf("\n"); break;

default:

putchar('.'); break;

}

fflush(stdout);

}

}

static OFString

makeUID(OFString basePrefix, int counter)

{

OFString prefix = basePrefix + "." + intToString(counter);

char uidbuf[65];

OFString uid = dcmGenerateUniqueIdentifier(uidbuf, prefix.c_str());

return uid;

}

static int

secondsSince1970()

{

time_t t = time(NULL);

return (int)t;

}

static OFString

intToString(int i)

{

char numbuf[32];

sprintf(numbuf, "%d", i);

return numbuf;

}

static OFBool

updateStringAttributeValue(DcmItem* dataset, const DcmTagKey& key, OFString& value)

{

DcmStack stack;

DcmTag tag(key);

OFCondition cond = EC_Normal;

cond = dataset->search(key, stack, ESM_fromHere, OFFalse);

if (cond != EC_Normal) {

CERR << "error: updateStringAttributeValue: cannot find: " << tag.getTagName()

<< " " << key << ": "

<< cond.text() << endl;

return OFFalse;

}

DcmElement* elem = (DcmElement*) stack.top();

DcmVR vr(elem->ident());

if (elem->getLength() > vr.getMaxValueLength()) {

CERR << "error: updateStringAttributeValue: INTERNAL ERROR: " << tag.getTagName()

<< " " << key << ": value too large (max "

<< vr.getMaxValueLength() << ") for " << vr.getVRName() << " value: " << value << endl;

return OFFalse;

}

cond = elem->putOFStringArray(value);

if (cond != EC_Normal) {

CERR << "error: updateStringAttributeValue: cannot put string in attribute: " << tag.getTagName()

<< " " << key << ": "

<< cond.text() << endl;

return OFFalse;

}

return OFTrue;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: