From 0928b363175e554f311cec5a173374d8ede1a7df Mon Sep 17 00:00:00 2001 From: jpr Date: Wed, 1 Sep 2010 14:40:00 +0000 Subject: [PATCH] Small exe, for unaware users --- Example/BrukerToMhd.cxx | 519 ++++++++++++++++++++++ Example/SingleFrames2Multiframe.cxx | 279 ++++++++++++ Example/exExplorePresentationState.cxx | 570 +++++++++++++++++++++++++ 3 files changed, 1368 insertions(+) create mode 100644 Example/BrukerToMhd.cxx create mode 100644 Example/SingleFrames2Multiframe.cxx create mode 100644 Example/exExplorePresentationState.cxx diff --git a/Example/BrukerToMhd.cxx b/Example/BrukerToMhd.cxx new file mode 100644 index 00000000..a4be43e3 --- /dev/null +++ b/Example/BrukerToMhd.cxx @@ -0,0 +1,519 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: BrukerToMhd.cxx,v $ + Language: C++ + Date: $Date: 2010/09/01 14:40:00 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +/** + * Writes an old style Bruker Dicom file, InTag compliant, from a Raw File + * User has to supply parameters. + * + */ +#include "gdcmFile.h" +#include "gdcmFileHelper.h" +#include "gdcmDebug.h" +#include "gdcmUtil.h" +#include "gdcmDirList.h" + +#include "gdcmArgMgr.h" + +#include +#include + +void DealWithNiveau1(std::string level1Directory); +void DealWithNiveau2(std::string level2Directory); +void DealWithNiveau3(std::string level3Directory); +/** + * \brief + * - explores the given root directory e.g. : + * B67d1.Bp1 + * subject + * AdjStatePerStudy + * 1 + * acqp + * fid + * imnd + * pulseprogram + * spnam0 + * spnam1 + * pdata + * 1 + * 2dseq + * d3proc + * isa + * meta + * procs + * roi + * 2 + * ... + * + * 2 + * acqp + * fid + * ... + * pdata + * 3 + * ... + * - fills a single level Directory with *all* the files, + * converted into a Brucker-like Dicom, Intags compliant + */ + + + + +int main(int argc, char *argv[]) +{ + START_USAGE(usage) + " \n BrukerToMhd : \n ", + " - explores the given directory, at the 3 levels, ", + " - fills an equivalent Directory with the MHD files, ", + " converted into a Brucker-like Dicom, InTags compliant ", + " usage: BrukerToMhd dirin=rootDirectoryName ", + " dirout=outputDirectoryName ", + " [{b|l}] b:BigEndian,l:LittleEndian default : l ", + " [debug] [verbose] [listonly] ", + " ", + " debug : developper wants to run the program in 'debug mode' ", + FINISH_USAGE + + + // ------------ Initialize Arguments Manager ---------------- + GDCM_NAME_SPACE::ArgMgr *am= new GDCM_NAME_SPACE::ArgMgr(argc, argv); + + if (argc == 1 || am->ArgMgrDefined("usage") ) + { + am->ArgMgrUsage(usage); // Display 'usage' + delete am; + return 1; + } + + const char *dirNamein; + dirNamein = am->ArgMgrGetString("dirin","."); + + const char *dirNameout; + dirNameout = am->ArgMgrGetString("dirout","."); + + int b = am->ArgMgrDefined("b"); + int l = am->ArgMgrDefined("l"); + + if (am->ArgMgrDefined("debug")) + GDCM_NAME_SPACE::Debug::DebugOn(); + + int verbose = am->ArgMgrDefined("verbose"); + int listonly = am->ArgMgrDefined("listonly"); + + /* if unused Param we give up */ + if ( am->ArgMgrPrintUnusedLabels() ) + { + am->ArgMgrUsage(usage); + delete am; + return 1; + } + + delete am; // we don't need Argument Manager any longer + + // ----------- End Arguments Manager --------- + + + // ----- Begin Processing ----- + + + bool bigEndian = GDCM_NAME_SPACE::Util::IsCurrentProcessorBigEndian(); + + + if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirNamein) ) + { + std::cout << "KO : [" << dirNamein << "] is not a Directory." << std::endl; + return 0; + + } + else + { + std::cout << "OK : [" << dirNamein << "] is a Directory." << std::endl; + } + + std::string systemCommand; + + std::cout << "Check for output directory :[" << dirNameout << "]." + <read((char*)pixels, (size_t)dataSizeIn); + + if ( pixelSize !=1 && ( (l && bigEndian) || (b && ! bigEndian) ) ) + { + ConvertSwapZone(pixelSize, pixels, dataSizeIn); + } + +if (verbose) + std::cout << "After ConvertSwapZone" << std::endl; + +// Copy (and convert) pixels of a single plane + + switch ( pixelTypeCode ) + { + case 8 : CFR(PU8); break; + case -8 : CFR(PS8); break; + case -16 : CFR(PU16); break; + case 16 : CFR(PS16); break; + case -32 : CFR(PS32); break; + case 32 : CFR(PU32); break; + case 33 : CFR(PF32); break; + case 64 : CFR(PD64); break; + } + +if (verbose) + std::cout << "After CFR" << std::endl; + +// Create an empty FileHelper + + GDCM_NAME_SPACE::FileHelper *fileH = GDCM_NAME_SPACE::FileHelper::New(); + + // Get the (empty) image header. + GDCM_NAME_SPACE::File *fileToBuild = fileH->GetFile(); + + // 'Study Instance UID' + // The user is allowed to create his own Study, + // keeping the same 'Study Instance UID' for various images + // The user may add images to a 'Manufacturer Study', + // adding new Series to an already existing Study + + fileToBuild->InsertEntryString(strStudyUID,0x0020,0x000d,"UI"); // Study UID + + // 'Serie Instance UID' + // The user is allowed to create his own Series, + // keeping the same 'Serie Instance UID' for various images + // The user shouldn't add any image to a 'Manufacturer Serie' + // but there is no way no to prevent him for doing that + + fileToBuild->InsertEntryString(strSerieUID,0x0020,0x000e,"UI"); // Serie UID + + std::ostringstream str; + + // Set the image size + str.str(""); + str << nX; + fileToBuild->InsertEntryString(str.str(),0x0028,0x0011, "US"); // Columns + str.str(""); + str << nY; + fileToBuild->InsertEntryString(str.str(),0x0028,0x0010, "US"); // Rows + + if (verbose) + std::cout << "before debut des choses serieuses2"<< std::endl; + +// str.str(""); +// str << nZ; +// fileToBuild->InsertEntryString(str.str(),0x0028,0x0008, "IS"); // Number of Frames + + // Set the pixel type + + str.str(""); + str << pixelSizeOut*8; + fileToBuild->InsertEntryString(str.str(),0x0028,0x0100, "US"); // Bits Allocated + + str.str(""); + str << pixelSizeOut*8; + fileToBuild->InsertEntryString(str.str(),0x0028,0x0101, "US"); // Bits Stored + + str.str(""); + str << ( pixelSizeOut*8 - 1 ); + fileToBuild->InsertEntryString(str.str(),0x0028,0x0102, "US"); // High Bit + + str.str(""); + str << pixelSign; + fileToBuild->InsertEntryString(str.str(),0x0028,0x0103, "US"); // Pixel Representation + +// If you deal with a Serie of images, as slices of a volume, +// it's up to you to tell gdcm, for each image, what are the values of : +// +// 0020 0032 DS 3 Image Position (Patient) +// 0020 0037 DS 6 Image Orientation (Patient) + + str.str(""); + str << "0.0\\0.0\\0.0"; + +// take Frame Index as position (we don't know anything else) NO! + + fileToBuild->InsertEntryString(str.str(),0x0020,0x0032, "DS"); + + fileToBuild->InsertEntryString("1.0\\0.0\\0.0\\0.0\\1.0\\0.0",0x0020,0x0037, "DS"); //[1\0\0\0\1\0] : Axial + + + + + str.str(""); + str << samplesPerPixel; + fileToBuild->InsertEntryString(str.str(),0x0028,0x0002, "US"); // Samples per Pixel + + if (strlen(patientName) != 0) + fileToBuild->InsertEntryString(patientName,0x0010,0x0010, "PN"); // Patient's Name + + // 0=white + if(monochrome1) + fileH->SetPhotometricInterpretationToMonochrome1(); + +// Special InTag, now. + + fileH->InsertEntryString(chSessionIndex, 0x0020, 0x0012, "IS"); + + // Deal with 0x0021, 0x1020 : 'SLICE INDEX' + // will stay to 0, since the stuff deals with single slice directories + char chSliceIndex[5]; + sprintf(chSliceIndex, "%04d", sliceIndex); + std::string strChSliceIndex(chSliceIndex); + + // Deal with 0x0021, 0x1040 : 'FRAME INDEX' + + str.str(""); + str << frameIndex; + frameIndex++; // be ready for next one + + fileH->InsertEntryString(strChSliceIndex, 0x0021, 0x1020, "IS"); + fileH->InsertEntryString(str.str(), 0x0021, 0x1040, "IS"); + + // Pixel Size + /// \TODO Ask user to supply 'Pixel Size' value + float pxSzX = 1.0; + float pxSzY = 1.0; + + // Field of view + char fov[64]; + sprintf(fov, "%f\\%f",nX*pxSzX, nY*pxSzY); + fileH->InsertEntryString(fov, 0x0019, 0x1000, "DS"); + + +// Set the image Pixel Data + fileH->SetImageData(planePixelsOut,singlePlaneDataSize); + +// Set the writting mode and write the image + fileH->SetWriteModeToRaw(); + + + + // Write a DICOM Explicit VR file + fileH->SetWriteTypeToDcmExplVR(); + + + outputFileName = strDirNameout + GDCM_NAME_SPACE::GDCM_FILESEPARATOR + *it + "_ForInTag.dcm"; + if( !fileH->Write(outputFileName ) ) + { + std::cout << "Failed for [" << outputFileName << "]\n" + << " File is unwrittable\n"; + } + +// End of : for (GDCM_NAME_SPACE::DirListType::iterator it = fileNames.begin() ... + + + + fileH->Delete(); + + delete[] pixels; + delete[] planePixelsOut; + } +*/ + // return 1; + } // end of : for (GDCM_NAME_SPACE::DirListType::iterator it + + + +void DealWithNiveau1(std::string level1Directory){ + + GDCM_NAME_SPACE::DirList dirList(level1Directory, false, true); // DON'T get recursively the list of files + + GDCM_NAME_SPACE::DirListType fileNames; + fileNames = dirList.GetFilenames(); + // ----------------------------------------------------- + // Iterate to ALL the objets(files/directories) found in the input directory + // ----------------------------------------------------- + GDCM_NAME_SPACE::DirListType::iterator it; + + for (it = fileNames.begin(); + it != fileNames.end(); + ++it) + { + if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(*it) ) + { + std::cout << "--- [" << *it << "] is a file" << std::endl; + } + + } + + for (it = fileNames.begin(); + it != fileNames.end(); + ++it) + { + if ( GDCM_NAME_SPACE::DirList::IsDirectory(*it) ) + { + std::cout << "--- [" << *it << "] is a directory" << std::endl; + DealWithNiveau2(*it); + } + } +} + + +void DealWithNiveau2(std::string level2Directory){ + + GDCM_NAME_SPACE::DirList dirList(level2Directory, false, true); // DON'T get recursively the list of files + + GDCM_NAME_SPACE::DirListType fileNames; + fileNames = dirList.GetFilenames(); + + // ----------------------------------------------------- + // Iterate to ALL the objets(files/directories) found in the input directory + // ----------------------------------------------------- + GDCM_NAME_SPACE::DirListType::iterator it; + + for (it = fileNames.begin(); + it != fileNames.end(); + ++it) + { + if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(*it) ) + { + std::cout << "--- --- [" << *it << "] is a file" << std::endl; + } + + } + + for (it = fileNames.begin(); + it != fileNames.end(); + ++it) + { + if ( GDCM_NAME_SPACE::DirList::IsDirectory(*it) ) + { + std::cout << "--- --- [" << *it << "] is a directory" << std::endl; + DealWithNiveau3(*it); + } + } +} + + +void DealWithNiveau3(std::string level3Directory){ + + GDCM_NAME_SPACE::DirList dirList(level3Directory, false, true); // DON'T get recursively the list of files + + GDCM_NAME_SPACE::DirListType fileNames; + fileNames = dirList.GetFilenames(); + + // ----------------------------------------------------- + // Iterate fo ALL the directories found in the input directory + // ----------------------------------------------------- + + for (GDCM_NAME_SPACE::DirListType::iterator it = fileNames.begin(); + it != fileNames.end(); + ++it) + { + + if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(*it) ) + { + std::cout << "--- --- --- [" << *it << "] is a file" << std::endl; + } + else + { + std::cout << "--- --- --- [" << *it << "] is a directory" << std::endl; + + } + } +} diff --git a/Example/SingleFrames2Multiframe.cxx b/Example/SingleFrames2Multiframe.cxx new file mode 100644 index 00000000..b0e15356 --- /dev/null +++ b/Example/SingleFrames2Multiframe.cxx @@ -0,0 +1,279 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: SingleFrames2Multiframe.cxx,v $ + Language: C++ + Date: $Date: 2010/09/01 14:40:00 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "gdcmFile.h" +#include "gdcmDocument.h" +#include "gdcmSeqEntry.h" +#include "gdcmSQItem.h" +#include "gdcmDataEntry.h" +#include "gdcmUtil.h" + +#include "gdcmFileHelper.h" +#include "gdcmDebug.h" +#include "gdcmDirList.h" +#include "gdcmGlobal.h" +#include "gdcmDictSet.h" +#include "gdcmArgMgr.h" +#include "gdcmOrientation.h" +#include + +#include + +int main(int argc, char *argv[]) +{ + + START_USAGE(usage) + " \n SingleFrames2Multiframe : \n ", + " Converts a directory holding a set of SingleFrames to a Multiframe file", + " usage: SingleFrames2Multiframe {dirin=inputDirectoryName} ", + " fileout=nomDuFichierMultiframe ", + + " [debug] [warning] ", + " studyUID : *aware* user wants to add the serie ", + " to an already existing study ", + " serieUID : *aware* user wants to give his own serie UID ", + " debug : user wants to run the program in 'debug mode' ", + " warning : user wants to be warned about any oddity in the File ", + FINISH_USAGE + + // Initialize Arguments Manager + GDCM_NAME_SPACE::ArgMgr *am= new GDCM_NAME_SPACE::ArgMgr(argc, argv); + + if (argc == 1 || am->ArgMgrDefined("usage") ) + { + am->ArgMgrUsage(usage); // Display 'usage' + delete am; + return 1; + } + + const char *dirName = am->ArgMgrGetString("dirin"); + + if (dirName == 0 ) + { + std::cerr << std::endl + << "'dirin=' must be present;"; + am->ArgMgrUsage(usage); // Display 'usage' + delete am; + return 1; + } + + const char *outputFileName = am->ArgMgrGetString("fileout"); + if (outputFileName == 0 ) + { + std::cerr << std::endl + << "'fileout=' must be present;" ; + am->ArgMgrUsage(usage); // Display 'usage' + delete am; + return 1; + } + + if (am->ArgMgrDefined("debug")) + GDCM_NAME_SPACE::Debug::DebugOn(); + + if (am->ArgMgrDefined("warning")) + GDCM_NAME_SPACE::Debug::WarningOn(); + + bool userDefinedStudy = ( 0 != am->ArgMgrDefined("studyUID") ); + const char *studyUID; + if (userDefinedStudy) + studyUID = am->ArgMgrGetString("studyUID"); + + // not described *on purpose* in the Usage ! + bool userDefinedSerie = ( 0 != am->ArgMgrDefined("serieUID") ); + const char *serieUID; + if(userDefinedSerie) + serieUID = am->ArgMgrGetString("serieUID"); + + /* if unused Param we give up */ + if ( am->ArgMgrPrintUnusedLabels() ) + { + am->ArgMgrUsage(usage); + delete am; + return 1; + } + + delete am; // we don't need Argument Manager any longer + + // ----------- End Arguments Manager --------- + + + GDCM_NAME_SPACE::DirList dirList(dirName,false); // gets recursively (or not) the file list + GDCM_NAME_SPACE::DirListType fileList = dirList.GetFilenames(); + GDCM_NAME_SPACE::File *f; + + bool res; + + if (fileList.size() == 0) + { + std::cout << "No file found in : [" << dirName << "]" << std::endl; + exit(0); + } + + // Order on file name (no pertinent info within header for 'secondary capture storage' images + //fileList.sort(); + std::sort( fileList.begin(), fileList.end() ); + + f = GDCM_NAME_SPACE::File::New(); + f->SetFileName( fileList[0].c_str() ); + res = f->Load(); + + // if first file is not gdcm-readable, we give up. + // (maybe we should check *all* the files ...) + + if (!res) + { + std::cout << "Cannot process file [" << fileList[0].c_str() << "]" + << std::endl; + std::cout << "Either it doesn't exist, or it's read protected " + << std::endl; + std::cout << "or it's not a Dicom File, or its 'header' is bugged" + << std::endl; + std::cout << "use 'PrintFile filein=... debug' " + << "to try to guess the pb" + << std::endl; + f->Delete(); + exit(0); + } + + int nX = f->GetXSize(); + int nY = f->GetYSize(); + int nZ = fileList.size(); + int pxSz = f->GetPixelSize(); + int sPP = f->GetSamplesPerPixel(); + + std::string stud= f->GetEntryString(0x0020,0x000d ); + std::cout << "------------------------------------------------ Study UID " << stud << std::endl; + + + std::cout << "First file nX " << nX << " nY " << nY << " nZ " << nZ << " pxSz " << pxSz << " sPP " << sPP << std::endl; + std::cout << "Image size " << nX*nY*pxSz*sPP << std::endl; + + char *imageBuffer; // = new char[nX*nY*pxSz]; + char *globalBuffer = new char[nX*nY*nZ*pxSz*sPP]; + + int i = 0; // image counter + for( GDCM_NAME_SPACE::DirListType::iterator it = fileList.begin(); + it != fileList.end(); + ++it ) + { + std::cout << std::endl<<" Start processing :[" << it->c_str() << "]" + << std::endl; + f = GDCM_NAME_SPACE::File::New(); + f->SetFileName( it->c_str() ); + res = f->Load(); + + if ( !res ) + { + std::cout << "Cannot process file [" << it->c_str() << "]" + << std::endl; + std::cout << "Either it doesn't exist, or it's read protected " + << std::endl; + std::cout << "or it's not a Dicom File, or its 'header' is bugged" + << std::endl; + std::cout << "use 'PrintFile filein=... debug' " + << "to try to guess the pb" + << std::endl; + f->Delete(); + continue; + } + + GDCM_NAME_SPACE::FileHelper *fh = GDCM_NAME_SPACE::FileHelper::New(f); + imageBuffer = (char *)fh->GetImageData(); + int lgr = fh->GetImageDataSize(); + + // we check all the files are consistent with the first one + if ( lgr != nX*nY*pxSz*sPP) + { + std::cout << "File : [" << it->c_str() << "] inconsistent with first one (lgr " << lgr << " vs " << nX*nY*pxSz*sPP<< "); ignored!" << std::endl; + continue; + } + else + + { + memcpy(globalBuffer+i*nX*nY*pxSz*sPP, imageBuffer, lgr ); + i++; + } + fh->Delete(); + } + + GDCM_NAME_SPACE::FileHelper *fh2 = GDCM_NAME_SPACE::FileHelper::New(); + + std::string strStudyUID; + std::string strSerieUID; + + if (userDefinedStudy) + strSerieUID = studyUID; + else + { + //strStudyUID = GDCM_NAME_SPACE::Util::CreateUniqueUID(); + + strStudyUID = stud; + } + + if (userDefinedSerie) + strSerieUID = serieUID; + else + strSerieUID = GDCM_NAME_SPACE::Util::CreateUniqueUID(); + + char temp[64]; + + sprintf(temp, "%d", sPP); + fh2->InsertEntryString(temp,0x0028,0x0002, "US"); // Samples per Pixel + + sprintf(temp, "%d", nY); + fh2->InsertEntryString(temp,0x0028,0x0010, "US"); // Number of Rows + + sprintf(temp, "%d", nX); + fh2->InsertEntryString(temp,0x0028,0x0011, "US"); // Number of Columns + + sprintf(temp, "%d", nZ); + fh2->InsertEntryString(temp,0x0028,0x0008, "IS"); // Number of Frames + + sprintf(temp, "%d", pxSz*8); + fh2->InsertEntryString(temp,0x0028,0x0100, "US"); // Bits Allocated + + + + // 'Study Instance UID' + // The user is allowed to create his own Study, + // keeping the same 'Study Instance UID' for various images + // The user may add images to a 'Manufacturer Study', + // adding new Series to an already existing Study + + fh2->InsertEntryString(strStudyUID,0x0020,0x000d,"UI"); // Study UID + + // 'Serie Instance UID' + // The user is allowed to create his own Series, + // keeping the same 'Serie Instance UID' for various images + // The user shouldn't add any image to a 'Manufacturer Serie' + // but there is no way no to prevent him for doing that + + fh2->InsertEntryString(strSerieUID,0x0020,0x000e,"UI"); // Serie UID + + // Set the image Pixel Data + fh2->SetUserData((uint8_t *)globalBuffer, nX*nY*pxSz*sPP*nZ); + + res = fh2->Write(outputFileName); + + if(!res) + std::cout <<"Fail to write [" << outputFileName << "]" <Delete(); + fh2->Delete(); + + return 0; +} diff --git a/Example/exExplorePresentationState.cxx b/Example/exExplorePresentationState.cxx new file mode 100644 index 00000000..16a2e3db --- /dev/null +++ b/Example/exExplorePresentationState.cxx @@ -0,0 +1,570 @@ + + /*========================================================================= + + Program: gdcm + Module: $RCSfile: exExplorePresentationState.cxx,v $ + Language: C++ + Date: $Date: 2010/09/01 14:40:00 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "gdcmFile.h" + +#include "gdcmArgMgr.h" + +#include "gdcmSeqEntry.h" +#include "gdcmSQItem.h" +#include "gdcmDocEntrySet.h" +//#include "gdcmSerieHelper.h" +#include "gdcmDirList.h" +#include "gdcmUtil.h" + +typedef struct { + // 0020|0013 [IS] [Instance Number] + std::string referencedInstanceNumber; + // 0004|1500 [CS] [Referenced File ID] + std::string referencedFileName; +} FILEINFO; + + + GDCM_NAME_SPACE::SeqEntry *CheckIfSequenceExists(GDCM_NAME_SPACE::File *fPS, uint16_t gr, uint16_t el); + GDCM_NAME_SPACE::SeqEntry *CheckIfSequenceExists(GDCM_NAME_SPACE::SQItem *si, uint16_t gr, uint16_t el); + bool dealWithCurrentFile(const char *PSName); + bool dealWithTopLevelItem(GDCM_NAME_SPACE::SQItem* currentItem); + bool dealWithEndLevelItem(GDCM_NAME_SPACE::SQItem* currentItem); + void displaySeekResult(GDCM_NAME_SPACE::SeqEntry* currentItem, uint16_t g, uint16_t e); + bool dealWithSequence(GDCM_NAME_SPACE::SeqEntry* se); + std::string dealWithReferencedFile(GDCM_NAME_SPACE::SQItem *si); + std::map dealWithDicomDir(const char *dicomdirname); + +bool verbose; +bool PSNameAlreadyShown; +std::map m; +std::string currentPSFileName; + + +int main(int argc, char *argv[]) +{ + START_USAGE(usage) + "\n exExplorePresentationState :\n ", + FINISH_USAGE + + + // ----- Initialize Arguments Manager ------ + + GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv); + + if (am->ArgMgrDefined("usage") || argc == 1) + { + am->ArgMgrUsage(usage); // Display 'usage' + delete am; + return 0; + } + + if (am->ArgMgrDefined("debug")) + GDCM_NAME_SPACE::Debug::DebugOn(); + + /*bool */verbose = am->ArgMgrDefined("verbose"); + bool rec = ( 0 != am->ArgMgrDefined("rec") ); + + const char *dirName = am->ArgMgrGetString("dirin"); + const char *dicomdirname = am->ArgMgrGetString("dicomdir"); + + /* if unused Param we give up */ + if ( am->ArgMgrPrintUnusedLabels() ) + { + am->ArgMgrUsage(usage); + delete am; + return 0; + } + delete am; // ------ we don't need Arguments Manager any longer ------ + + // =========================================================================== + // ========================= Deal with the relevant DICOMDIR ================= + // =========================================================================== + + + /*std::map */ m = dealWithDicomDir(dicomdirname); + + // =========================================================================== + // ========================= Deal with the Directory holding DICOM images == + // =========================================================================== + + std::cout << " Image Directory Name [" << dirName << "]\n\n" << std::endl; + + GDCM_NAME_SPACE::DirList dirList(dirName,rec); // gets recursively (or not) the file list + GDCM_NAME_SPACE::DirListType fileList = dirList.GetFilenames(); + GDCM_NAME_SPACE::File *f; + bool res; + + if (fileList.size() == 0) + { + std::cout << "No file found in : [" << dirName << "]" << std::endl; + } + + for( GDCM_NAME_SPACE::DirListType::iterator it = fileList.begin(); + it != fileList.end(); + ++it ) + { + + currentPSFileName = it->c_str(); + if (verbose) + std::cout << std::endl<<" Start processing :[" << it->c_str() << "]" + << std::endl; + f = GDCM_NAME_SPACE::File::New(); + //f->SetLoadMode(loadMode); + f->SetFileName( it->c_str() ); + + res = f->GDCM_NAME_SPACE::Document::Load(); + + if ( !res ) + { + if (verbose) + { + std::cout << "Cannot process file [" << it->c_str() << "]" + << std::endl; + std::cout << "Either it doesn't exist, or it's read protected " + << std::endl; + std::cout << "or it's not a Dicom File, or its 'header' is bugged" + << std::endl; + std::cout << "use 'PrintFile filein=... debug' " + << "to try to guess the pb" + << std::endl; + } + f->Delete(); + continue; + } + + bool resFile = dealWithCurrentFile(it->c_str()); + if (verbose) + std::cout << "\n\n" <c_str() << "]==" << resFile << std::endl; + //return resFile; + + continue; + + } +} + + + +//---------------------------------------------------------------------------------------------------- +bool dealWithCurrentFile(const char *PSName) +{ + + GDCM_NAME_SPACE::File *fPS = GDCM_NAME_SPACE::File::New( ); + fPS->SetFileName( PSName ); + fPS->SetMaxSizeLoadEntry(0xffff); + bool res2 = fPS->Load(); + + if (!res2) { + if (verbose) + std::cout << "Sorry, " << PSName << " not a gdcm-readable " + << "DICOM / ACR File" + << std::endl; + fPS->Delete(); + return false; + } + + GDCM_NAME_SPACE::SeqEntry *se; + + se = CheckIfSequenceExists( fPS, 0x0070, 0x0001); + //displaySeekResult(se, 0x0070, 0x0001); + if (!se) + { + if (verbose) + std::cout << "[" << PSName << "] : Hopeless (" << std::hex << 0x0070 << "|" << 0x0001 << std::dec << " doesn't exist...)" <GetFirstSQItem(); // Get the first 'ROI' + if (currentItem == NULL) + { + if (verbose) + std::cout << "======== Deal With NOTHING! (Sequence 0070|0001 [Graphic Annotation Sequence] has NO item ?!?) within " + << PSName << "]" << std::endl; + return false; + } + int i =0; + bool res3; + bool finalRes = false; + while (currentItem != NULL) + { + if (verbose) + std::cout << "======== Deal With 'ROI' n." << i << std::endl; + + // do what you want with the current 'ROI' + res3 = dealWithTopLevelItem(currentItem); + if (res3) + finalRes = true; + //... + + currentItem = se->GetNextSQItem(); // Get the next 'ROI' + i++; + } + + if (finalRes) + std::cout << "=============================(within PS File :[" << PSName << "]\n\n" << std::endl; + fPS->Delete(); + + if(verbose) + std::cout << "\n\n" <GetGroup(); + uint16_t e = se->GetElement(); + if (verbose) + std::cout << std::hex << "\n------------------------ deal with " << g <<"|" << e << std::dec + << " " << se->GetName() << std::endl; + + GDCM_NAME_SPACE::SQItem *si = se->GetFirstSQItem(); + if (!si) { + if (verbose) + std::cout << "Sequence " << std::hex << g <<"|" << e << std::dec << "has no Item ?!?" << std::endl; + return false; + } + std::string referencedFileUID; + //std::cout << "\n============================== [" << currentPSFileName << "] =================" << std::endl; + if (g == 0x0008) { + if (verbose) + si->Print(std::cout); + referencedFileUID = dealWithReferencedFile(si); +// std::cout << " referencedFile UID[" << referencedFileUID <<"]" << std::endl; + + } else if (g == 0x0070) { + if (verbose) + si->Print(std::cout); + } else { + if (verbose) + std::cout << "Unexpected Group " << std::hex << g << std::hex << std::endl; + } + + si = se->GetNextSQItem(); + if (si) + { + if (verbose) + std::cout << "Sequence " << std::hex << g <<"|" << e << std::dec << "should have only ONE Item ?!?" << std::endl; + // if (verbose) + // si->Print(std::cout); + return false; + } + return true; +} + +//---------------------------------------------------------------------------------------------------- + +void displaySeekResult(GDCM_NAME_SPACE::SeqEntry* se, uint16_t g, uint16_t e) +{ + if (se) + { + // std::cout << std::hex << g << "|" << e << std::dec << " [" << se->GetName() << "] exists" <GetSeqEntry(gr, el); + return se; +} + +// ---------------------------------------------------------------------------------- + +GDCM_NAME_SPACE::SeqEntry *CheckIfSequenceExists( GDCM_NAME_SPACE::SQItem *si, uint16_t gr, uint16_t el) +{ + GDCM_NAME_SPACE::SeqEntry *se= si->GetSeqEntry(gr, el); + return se; +} + +// ---------------------------------------------------------------------------------- + +std::string dealWithReferencedFile(GDCM_NAME_SPACE::SQItem *si) +{ + // GDCM_NAME_SPACE::DocEntry *si = GetDocEntry(0x0008, 0x1155); + + // Look for : 0004|1511 [UI] [Referenced SOP Instance UID in File] + std::string referencedFileUID = si->GetEntryString(0x0008, 0x1155); + // std::cout << " referencedFile UID[" << referencedFileUID <<"]" << std::endl; + + if (verbose) + std::cout << "m[" << referencedFileUID << "] = "; + + std::cout << "[" << m[referencedFileUID].referencedInstanceNumber << "] [" << m[referencedFileUID].referencedFileName << "]" << std::endl; + + return referencedFileUID; + +} + +// ---------------------------------------------------------------------------------- +std::map dealWithDicomDir(const char *dicomdirname) +{ + FILEINFO fi; + GDCM_NAME_SPACE::File *f; + bool res; + std::map m; + + std::cout << std::endl<<" Start reading DICOMDIR :[" << dicomdirname << "]" + << std::endl; + + f = GDCM_NAME_SPACE::File::New(); + //f->SetLoadMode(loadMode); + f->SetFileName( dicomdirname ); + + // Don't load a DicomDir ! + res = f->GDCM_NAME_SPACE::Document::Load(); + + if ( !res ) + { + std::cout << "Cannot process file [" << dicomdirname << "]" + << std::endl; + std::cout << "Either it doesn't exist, or it's read protected " + << std::endl; + std::cout << "or it's not a Dicom File, or its 'header' is bugged" + << std::endl; + std::cout << "use 'PrintFile filein=... debug' " + << "to try to guess the pb" + << std::endl; + f->Delete(); + /// \TODO : throw an exception + return m;; + } + + // Get 0004|1220 [SQ] [Directory Record Sequence] + + GDCM_NAME_SPACE::SeqEntry *dsr= f->GetSeqEntry(0x0004,0x1220); + if (!dsr) + { + if (verbose) + std::cout << "[" << dicomdirname << "] : Hopeless (" << std::hex << 0x0094 << "|" << 0x01220 + << std::dec << " -Directory Record Sequence- doesn't exist...)" <Delete(); + /// \TODO : throw an exception + return m; + } + + GDCM_NAME_SPACE::SQItem* currentItem = dsr->GetFirstSQItem(); // Get the first 'ROI' + if (currentItem == NULL) + { + if (verbose) + std::cout << "======== Deal With NOTHING! (Sequence 0004|1220 [Directory Record Sequence] has NO item ?!?)" << std::endl; + /// \TODO : throw an exception + return m; + } + + int i =0; + while (currentItem != NULL) + { + // Get 0020|0013 [IS] [Instance Number] + fi.referencedInstanceNumber = currentItem->GetEntryString(0x0020, 0x0013); + + // Get 0004|1500 [CS] [Referenced File ID] + fi.referencedFileName = currentItem->GetEntryString(0x0004, 0x1500); + + // Get0004|1511 [UI] [Referenced SOP Instance UID in File] + std::string referencedFileSopInstanceUID = currentItem->GetEntryString(0x0004, 0x1511); + + m[referencedFileSopInstanceUID] = fi; + currentItem = dsr->GetNextSQItem(); // Get the next 'ROI' + i++; + } + + if (verbose) + for(std::map::iterator it = m.begin(); it != m.end(); ++it) + { + std::cout << "m[" << (*it).first << "] = [" << (*it).second.referencedInstanceNumber << "] [" << (*it).second.referencedFileName << std::endl; + } + + return m; + +} -- 2.45.0