From 19c54f9be7d29dcdd8fbb56b6308e55ed230441d Mon Sep 17 00:00:00 2001 From: frog Date: Thu, 10 Jun 2004 13:28:53 +0000 Subject: [PATCH] * src/gdcmHeader.[cxx|h]: - Predicates on the Transfer syntax (of the form Is[JPEF|RLE]*) and related, moved away to gdcmDocument. - Accessors (on the form [Get|Set]Entry*) set up to expose publicly the corresponding protected accessors of inherited class gdcmDocument, removed ! As a consequence gdcmFile had to be declared friend of class gdcmDocument (see below). - operator< moved to gdcmDocument (in fact it belongs to gdcmDicomDir). - Clean up of undefined or unused methods. * src/gdcmFile.[cxx|h]: added SetEntryByNumber (in order to take into account the changes to gdcmHeader.h). * src/gdcmDocument.h: - gdcmFile is now a friend class (in order to take into account the changes to gdcmHeader.h). - Predicates on the Transfer syntax (of the form Is[JPEF|RLE]*) added (see changes to gdcmHeader.h). - Accessors (reading on the form GetEntry*) are now public. - Clean up of undefined or unused methods. * src/gdcmDocument.cxx: - adaptation to changes to gdcmDocument.h - ::OpenFile now writes a verbose message when file cannot be opened. - some std::string properly set to VRKey * src/gdcmDicomDir.h: historical references to gdcmHeader changed to references to gdcmDocument. * Test/TestFindTags.cxx: changed accordingly to above changes. * gdcmPython/testSuite.py: adapted to renaming of acr files in cvs repository gdcmData. --- ChangeLog | 29 +++++ gdcmPython/testSuite.py | 10 +- src/gdcm.h | 15 +-- src/gdcmDicomDir.cxx | 12 +- src/gdcmDicomDir.h | 12 +- src/gdcmDocument.cxx | 246 +++++++++++++++++++++++++++++++++------- src/gdcmDocument.h | 64 ++++------- src/gdcmFile.h | 9 +- src/gdcmHeader.cxx | 240 +-------------------------------------- src/gdcmHeader.h | 58 ---------- 10 files changed, 290 insertions(+), 405 deletions(-) diff --git a/ChangeLog b/ChangeLog index bb16ba9f..37ca0b88 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2004-06-10 Eric Boix + * src/gdcmHeader.[cxx|h]: + - Predicates on the Transfer syntax (of the form Is[JPEF|RLE]*) + and related, moved away to gdcmDocument. + - Accessors (on the form [Get|Set]Entry*) set up to expose publicly + the corresponding protected accessors of inherited class + gdcmDocument, removed ! As a consequence gdcmFile had to be + declared friend of class gdcmDocument (see below). + - operator< moved to gdcmDocument (in fact it belongs to gdcmDicomDir). + - Clean up of undefined or unused methods. + * src/gdcmFile.[cxx|h]: added SetEntryByNumber (in order to take into + account the changes to gdcmHeader.h). + * src/gdcmDocument.h: + - gdcmFile is now a friend class (in order to take into account the + changes to gdcmHeader.h). + - Predicates on the Transfer syntax (of the form Is[JPEF|RLE]*) added + (see changes to gdcmHeader.h). + - Accessors (reading on the form GetEntry*) are now public. + - Clean up of undefined or unused methods. + * src/gdcmDocument.cxx: + - adaptation to changes to gdcmDocument.h + - ::OpenFile now writes a verbose message when file cannot be opened. + - some std::string properly set to VRKey + * src/gdcmDicomDir.h: historical references to gdcmHeader changed to + references to gdcmDocument. + * Test/TestFindTags.cxx: changed accordingly to above changes. + * gdcmPython/testSuite.py: adapted to renaming of acr files in + cvs repository gdcmData. + 2004-06-09 Eric Boix * src/gdcmValEntry.h: member voidArea type changed from char* to void*. * src/gdcmBinEntry.h: member voidArea commented out, since it potentially diff --git a/gdcmPython/testSuite.py b/gdcmPython/testSuite.py index 3f0ccd3a..8ef87055 100644 --- a/gdcmPython/testSuite.py +++ b/gdcmPython/testSuite.py @@ -81,7 +81,7 @@ class gdcmTestCase(unittest.TestCase): ["Manufacturer", "FUJI"], ["Pixel Data", "gdcm::NotLoaded. Address:796 Length:262144 x(40000)"] ] ], - ["CT-MONO2-12-lomb-an2.acr2", + ["CT-MONO2-12-lomb-an2.acr", [ ["Modality", "CT"], #"Transfer Syntax UID" and "Photometric Interpretation" are absent. ["Rows", "512"], @@ -109,7 +109,7 @@ class gdcmTestCase(unittest.TestCase): #################################### ### MR modality examples: #################################### - ["MR-MONO2-12-angio-an1.acr1", + ["MR-MONO2-12-angio-an1.acr", [ ["Recognition Code (RET)", "ACR-NEMA 1.0"], ["Modality", "MR"], #"Transfer Syntax UID" and "Photometric Interpretation" are absent. @@ -123,7 +123,7 @@ class gdcmTestCase(unittest.TestCase): # Note: 256*256*12/8 = 98304 ["Pixel Data", "gdcm::NotLoaded. Address:650 Length:98304 x(18000)"] ] ], - ["MR-MONO2-12-an2.acr2", + ["MR-MONO2-12-an2.acr", [ ["Modality", "MR"], ["Photometric Interpretation", "MONOCHROME2"], ["Rows", "256"], @@ -310,7 +310,7 @@ class gdcmTestCase(unittest.TestCase): ] GdcmFiles = [ - ["gdcm-MR-SIEMENS-16.acr1", + ["gdcm-MR-SIEMENS-16-1.acr", # Interest: good old Acr-Nema Version 1, see also Oddities below [ ["Recognition Code (RET)", "ACR-NEMA 1.0"], ["Modality", "MR"], @@ -329,7 +329,7 @@ class gdcmTestCase(unittest.TestCase): ["Study ID", ""], ["Series Number", ""] ] ], # Oddities: "Study" and "Serie Instance UID" are not present - ["gdcm-MR-SIEMENS-16.acr2", + ["gdcm-MR-SIEMENS-16-2.acr", # Interest: Acr-Nema Version 2 [ ["Recognition Code (RET)", "ACR-NEMA 2.0"], ["Modality", "MR"], diff --git a/src/gdcm.h b/src/gdcm.h index 9aa9d3d4..fd2500fc 100644 --- a/src/gdcm.h +++ b/src/gdcm.h @@ -3,15 +3,8 @@ #ifndef GDCM_H #define GDCM_H -//----------------------------------------------------------------------------- -// Tag based hash tables. -// We shall use as keys the strings (as the C++ type) obtained by -// concatenating the group value and the element value (both of type -// unsigned 16 bit integers in Dicom) expressed in hexadecimal. -// Example: consider the tag given as (group, element) = (0x0010, 0x0010). -// Then the corresponding TagKey shall be the string 0010|0010 (where -// the | (pipe symbol) acts as a separator). -// Refer to gdcmDictEntry::TranslateToKey for this conversion function. +// General purpose include file. This file should be included by +// external users of gdcm. It exposes the necessary API. #include "gdcmException.h" #include "gdcmCommon.h" @@ -20,15 +13,11 @@ #include "gdcmDict.h" #include "gdcmDictSet.h" -//#include "gdcmParser.h" #include "gdcmDocument.h" -//#include "gdcmHeaderEntry.h" -//#include "gdcmDocEntry.h" #include "gdcmHeader.h" #include "gdcmHeaderHelper.h" #include "gdcmFile.h" #include "gdcmUtil.h" -//----------------------------------------------------------------------------- #endif diff --git a/src/gdcmDicomDir.cxx b/src/gdcmDicomDir.cxx index da2bf72b..5c508292 100644 --- a/src/gdcmDicomDir.cxx +++ b/src/gdcmDicomDir.cxx @@ -19,6 +19,7 @@ #include "gdcmUtil.h" #include "gdcmDebug.h" #include "gdcmGlobal.h" +#include "gdcmHeader.h" #include "gdcmSeqEntry.h" #include "gdcmSQItem.h" @@ -393,7 +394,7 @@ void gdcmDicomDir::CreateDicomDirChainedList(std::string path) gdcmDirList fileList(path,1); // gets recursively the file list unsigned int count=0; - ListHeader list; + VectDocument list; gdcmHeader *header; tagHT.clear(); @@ -511,7 +512,8 @@ gdcmDicomDirPatient * gdcmDicomDir::NewPatient(void) { * @param type gdcmObject type to create (GDCM_DICOMDIR_PATIENT, GDCM_DICOMDIR_STUDY, GDCM_DICOMDIR_SERIE ...) * @param header gdcmHeader of the current file */ -void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header) +void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type, + gdcmDocument *header) { std::list elemList; std::list::iterator it; @@ -841,7 +843,7 @@ void gdcmDicomDir::AddDicomDirSerieToEnd(gdcmSQItem *s) * @param path path of the root directory * @param list chained list of Headers */ -void gdcmDicomDir::SetElements(std::string &path, ListHeader &list) +void gdcmDicomDir::SetElements(std::string &path, VectDocument &list) { std::string patPrevName="", patPrevID=""; std::string studPrevInstanceUID="", studPrevID=""; @@ -853,7 +855,7 @@ void gdcmDicomDir::SetElements(std::string &path, ListHeader &list) SetElement(path,GDCM_DICOMDIR_META,NULL); - for(ListHeader::iterator it=list.begin();it!=list.end();++it) + for(VectDocument::iterator it=list.begin();it!=list.end();++it) { // get the current file characteristics patCurName= (*it)->GetEntryByNumber(0x0010,0x0010); @@ -890,7 +892,7 @@ void gdcmDicomDir::SetElements(std::string &path, ListHeader &list) * \ingroup gdcmDicomDir * \brief compares two dgcmHeaders */ -bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2) +bool gdcmDicomDir::HeaderLessThan(gdcmDocument *header1,gdcmDocument *header2) { return(*header1<*header2); } diff --git a/src/gdcmDicomDir.h b/src/gdcmDicomDir.h index 40bf6100..fdb03622 100644 --- a/src/gdcmDicomDir.h +++ b/src/gdcmDicomDir.h @@ -3,8 +3,9 @@ #ifndef GDCMDICOMDIR_H #define GDCMDICOMDIR_H -#include "gdcmHeader.h" +//#include "gdcmHeader.h" #include "gdcmCommon.h" +#include "gdcmDocument.h" #include "gdcmDicomDirPatient.h" #include "gdcmDicomDirMeta.h" #include "gdcmDicomDirElement.h" @@ -14,7 +15,7 @@ //----------------------------------------------------------------------------- typedef std::list ListDicomDirPatient; -typedef std::vector ListHeader; +typedef std::vector VectDocument; typedef GDCM_EXPORT void(gdcmMethod)(void * = NULL); //----------------------------------------------------------------------------- @@ -118,12 +119,13 @@ private: void AddDicomDirSerieToEnd (gdcmSQItem *s); void AddDicomDirImageToEnd (gdcmSQItem *s); - void SetElements(std::string &path,ListHeader &list); - void SetElement (std::string &path,gdcmDicomDirType type,gdcmHeader *header); + void SetElements(std::string &path, VectDocument &list); + void SetElement (std::string &path,gdcmDicomDirType type, + gdcmDocument *header); void UpdateDirectoryRecordSequenceLength(void); - static bool HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2); + static bool HeaderLessThan(gdcmDocument *header1,gdcmDocument *header2); // Variables diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index 3b4c2d4a..36f1e817 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -199,11 +199,13 @@ bool gdcmDocument::SetShaDict(DictKey dictName){ */ bool gdcmDocument::IsReadable(void) { if(filetype==gdcmUnknown) { - std::cout << "wrong filetype" <GetValue(); + if ( Transfer == "1.2.840.10008.1.2.4.50" ) + return true; + return false; +} + +/** + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a JPEGExtendedProcess2-4 one. + * @return True when JPEGExtendedProcess2-4 found. False in all other cases. + */ +bool gdcmDocument::IsJPEGExtendedProcess2_4TransferSyntax(void) { + gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadDocEntrySafe(Element); + return ( ((gdcmValEntry *)Element)->GetValue() == "1.2.840.10008.1.2.4.51" +);} + +/** + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a JPEGExtendeProcess3-5 one. + * @return True when JPEGExtendedProcess3-5 found. False in all other cases. + */ +bool gdcmDocument::IsJPEGExtendedProcess3_5TransferSyntax(void) { + gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadDocEntrySafe(Element); + + std::string Transfer = ((gdcmValEntry *)Element)->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.4.52" ) + return true; + return false; +} + +/** + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a JPEGSpectralSelectionProcess6-8 one. + * @return True when JPEGSpectralSelectionProcess6-8 found. False in all + * other cases. + */ +bool gdcmDocument::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) { + gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadDocEntrySafe(Element); + + std::string Transfer = ((gdcmValEntry *)Element)->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.4.53" ) + return true; + return false; +} + +/** + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a RLE Lossless one. + * @return True when RLE Lossless found. False in all + * other cases. + */ +bool gdcmDocument::IsRLELossLessTransferSyntax(void) { + gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadDocEntrySafe(Element); + + std::string Transfer = ((gdcmValEntry *)Element)->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.5" ) { + return true; + } + return false; +} + +/** + * \brief Determines if Transfer Syntax was already encountered + * and if it corresponds to a JPEG Lossless one. + * @return True when RLE Lossless found. False in all + * other cases. + */ +bool gdcmDocument::IsJPEGLossless(void) { + gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); + // faire qq chose d'intelligent a la place de ça + if ( !Element ) + return false; + LoadDocEntrySafe(Element); + + const char * Transfert = ((gdcmValEntry *)Element)->GetValue().c_str(); + + if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true; + if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true; + + if (((gdcmValEntry *)Element)->GetValue() == "1.2.840.10008.1.2.4.57") +return true; + + return false; +} + +/** + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a JPEG2000 one + * @return True when JPEG2000 (Lossly or LossLess) found. False in all + * other cases. + */ +bool gdcmDocument::IsJPEG2000(void) { + gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadDocEntrySafe(Element); + + std::string Transfer = ((gdcmValEntry *)Element)->GetValue(); + if ( (Transfer == "1.2.840.10008.1.2.4.90") + || (Transfer == "1.2.840.10008.1.2.4.91") ) + return true; + return false; +} + +/** + * \brief Predicate for dicom version 3 file. + * @return True when the file is a dicom version 3. + */ +bool gdcmDocument::IsDicomV3(void) { + // Checking if Transfert Syntax exists is enough + // Anyway, it's to late check if the 'Preamble' was found ... + // And ... would it be a rich idea to check ? + // (some 'no Preamble' DICOM images exist !) + return (GetDocEntryByNumber(0x0002, 0x0010) != NULL); +} + /** * \brief returns the File Type * (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown) @@ -296,10 +437,17 @@ FILE *gdcmDocument::OpenFile(bool exception_on_error) throw(gdcmFileError) { fp=fopen(filename.c_str(),"rb"); - if(exception_on_error) + + if(!fp) { - if(!fp) - throw gdcmFileError("gdcmDocument::gdcmDocument(const char *, bool)"); + if(exception_on_error) + throw gdcmFileError("gdcmDocument::gdcmDocument(const char *, bool)"); + else + { + dbg.Verbose(0, "gdcmDocument::OpenFile cannot open file: ", + filename.c_str()); + return (NULL); + } } if ( fp ) @@ -602,7 +750,7 @@ bool gdcmDocument::SetEntryByNumber(std::string content, ((gdcmValEntry*)a)->SetValue(content); - std::string vr = a->GetVR(); + VRKey vr = a->GetVR(); guint32 lgr; if( (vr == "US") || (vr == "SS") ) @@ -835,7 +983,7 @@ void gdcmDocument::WriteEntryTagVRLength(gdcmDocEntry *tag, FileType type) { guint16 group = tag->GetGroup(); - std::string vr = tag->GetVR(); + VRKey vr = tag->GetVR(); guint16 el = tag->GetElement(); guint32 lgr = tag->GetReadLength(); @@ -898,7 +1046,7 @@ void gdcmDocument::WriteEntryValue(gdcmDocEntry *tag, FILE *_fp,FileType type) { (void)type; guint16 group = tag->GetGroup(); - std::string vr = tag->GetVR(); + VRKey vr = tag->GetVR(); guint32 lgr = tag->GetReadLength(); if (vr == "SQ") @@ -2301,39 +2449,6 @@ gdcmDocEntry *gdcmDocument::NewDocEntryByNumber(guint16 Group, guint16 Elem) return NewEntry; } -/// \todo Never used; commented out, waiting for removal. -/** - * \brief Small utility function that creates a new manually crafted - * (as opposed as read from the file) gdcmDocEntry with user - * specified name and adds it to the public tag hash table. - * \note A fake TagKey is generated so the PubDict can keep it's coherence. - * @param NewTagName The name to be given to this new tag. - * @param VR The Value Representation to be given to this new tag. - * @return The newly hand crafted Element Value. - */ -//gdcmDocEntry *gdcmDocument::NewManualDocEntryToPubDict(std::string NewTagName, -// std::string VR) -//{ -// gdcmDocEntry *NewEntry = NULL; -// guint32 StuffGroup = 0xffff; // Group to be stuffed with additional info -// guint32 FreeElem = 0; -// gdcmDictEntry *DictEntry = NULL; -// -// FreeElem = GenerateFreeTagKeyInGroup(StuffGroup); -// if (FreeElem == UINT32_MAX) -// { -// dbg.Verbose(1, "gdcmHeader::NewManualDocEntryToPubDict", -// "Group 0xffff in Public Dict is full"); -// return NULL; -// } -// -// DictEntry = NewVirtualDictEntry(StuffGroup, FreeElem, -// VR, "GDCM", NewTagName); -// NewEntry = new gdcmDocEntry(DictEntry); -// AddEntry(NewEntry); -// return NewEntry; -//} - /** * \brief Generate a free TagKey i.e. a TagKey that is not present * in the TagHt dictionary. @@ -2621,6 +2736,55 @@ void gdcmDocument::Parse7FE0 (void) { return; } +/** + * \brief Compares two documents, according to \ref gdcmDicomDir rules + * \warning Does NOT work with ACR-NEMA files + * \todo Find a trick to solve the pb (use RET fields ?) + * @param document + * @return true if 'smaller' + */ + bool gdcmDocument::operator<(gdcmDocument &document){ + std::string s1,s2; + + // Patient Name + s1=this->GetEntryByNumber(0x0010,0x0010); + s2=document.GetEntryByNumber(0x0010,0x0010); + if(s1 < s2) + return(true); + else if(s1 > s2) + return(false); + else + { + // Patient ID + s1=this->GetEntryByNumber(0x0010,0x0020); + s2=document.GetEntryByNumber(0x0010,0x0020); + if (s1 < s2) + return(true); + else if (s1 > s2) + return(1); + else + { + // Study Instance UID + s1=this->GetEntryByNumber(0x0020,0x000d); + s2=document.GetEntryByNumber(0x0020,0x000d); + if (s1 < s2) + return(true); + else if(s1 > s2) + return(false); + else + { + // Serie Instance UID + s1=this->GetEntryByNumber(0x0020,0x000e); + s2=document.GetEntryByNumber(0x0020,0x000e); + if (s1 < s2) + return(true); + else if(s1 > s2) + return(false); + } + } + } + return(false); +} //----------------------------------------------------------------------------- diff --git a/src/gdcmDocument.h b/src/gdcmDocument.h index 27c61170..96a9aea3 100644 --- a/src/gdcmDocument.h +++ b/src/gdcmDocument.h @@ -25,10 +25,11 @@ typedef std::map VRHT; // Value Representation Hash Table //----------------------------------------------------------------------------- /** - * \brief used by both gdcmHeader and gdcmDicomDir + * \brief Derived by both gdcmHeader and gdcmDicomDir */ class GDCM_EXPORT gdcmDocument : public gdcmElementSet { +friend class gdcmFile; private: /// Public dictionary used to parse this header gdcmDict *RefPubDict; @@ -89,18 +90,7 @@ protected: int printLevel; public: - - -// Print - // Canonical Printing method (see also gdcmDocument::SetPrintLevel) - // virtual void Print (std::ostream &os = std::cout); - // {PrintEntry(os);}; - - // no more Print method for gdcmDocument (inherits from gdcmElementSet - // virtual void PrintEntry (std::ostream &os = std::cout) - // { return Print(os);}; - - // the 2 following will be merged +// the 2 following will be merged virtual void PrintPubDict (std::ostream &os = std::cout); virtual void PrintShaDict (std::ostream &os = std::cout); @@ -116,6 +106,15 @@ public: bool IsExplicitVRLittleEndianTransferSyntax(void); bool IsDeflatedExplicitVRLittleEndianTransferSyntax(void); bool IsExplicitVRBigEndianTransferSyntax(void); + bool IsJPEGBaseLineProcess1TransferSyntax(void); + bool IsJPEGExtendedProcess2_4TransferSyntax(void); + bool IsJPEGExtendedProcess3_5TransferSyntax(void); + bool IsJPEGSpectralSelectionProcess6_8TransferSyntax(void); + bool IsRLELossLessTransferSyntax(void); + bool IsJPEGLossless(void); + bool IsJPEG2000(void); + bool IsDicomV3(void); + FileType GetFileType(void); // Read (used in gdcmFile, gdcmDicomDir) @@ -149,20 +148,21 @@ protected: // gdcmDicomDir are meaningfull). gdcmDocument(bool exception_on_error = false); gdcmDocument(const char *inFilename, - bool exception_on_error = false, - bool enable_sequences = false, - bool ignore_shadow = false); + bool exception_on_error = false, + bool enable_sequences = false, + bool ignore_shadow = false); virtual ~gdcmDocument(void); void gdcmDocument::Parse7FE0 (void); // Entry int CheckIfEntryExistByNumber(guint16 Group, guint16 Elem ); // int ! +public: virtual std::string GetEntryByName (std::string tagName); virtual std::string GetEntryVRByName (std::string tagName); virtual std::string GetEntryByNumber (guint16 group, guint16 element); virtual std::string GetEntryVRByNumber(guint16 group, guint16 element); virtual int GetEntryLengthByNumber(guint16 group, guint16 element); - +protected: virtual bool SetEntryByName (std::string content, std::string tagName); virtual bool SetEntryByNumber(std::string content, guint16 group, guint16 element); @@ -181,22 +181,10 @@ protected: void LoadDocEntrySafe(gdcmDocEntry *); - // Probabely useless - //void UpdateGroupLength(bool SkipSequence = false, - // FileType type = ImplicitVR); - - //void AddDocEntry (gdcmDocEntry *); - - private: - // Read - //bool LoadHeaderEntries(bool exception_on_error = false) throw(gdcmFormatError); - // remplacé par ParseDES. - // What about exception_on_error ? - - long ParseDES(gdcmDocEntrySet *set, long offset, long l_max, bool delim_mode); - // long ParseSQ(gdcmDocEntrySet *set, long offset, long l_max, bool delim_mode); - long ParseSQ(gdcmSeqEntry *seq, long offset, long l_max, bool delim_mode); +// Read + long ParseDES(gdcmDocEntrySet *set, long offset, long l_max,bool delim_mode); + long ParseSQ(gdcmSeqEntry *seq, long offset, long l_max, bool delim_mode); void LoadDocEntry (gdcmDocEntry *); void FindDocEntryLength(gdcmDocEntry *); @@ -233,19 +221,12 @@ private: std::string vr = "unkn", std::string fourth = "unkn", std::string name = "unkn"); - //gdcmDictEntry *NewVirtualDictEntry(gdcmDocEntry *); // never defined - // DocEntry related utilities - gdcmDocEntry *ReadNextDocEntry (void); gdcmDocEntry *NewDocEntryByNumber(guint16 group, guint16 element); gdcmDocEntry *NewDocEntryByName (std::string Name); - // Deprecated (Not used) --> commented out - //gdcmDocEntry *NewManualDocEntryToPubDict(std::string NewTagName, - // std::string VR); - guint32 GenerateFreeTagKeyInGroup(guint16 group); public: @@ -262,15 +243,14 @@ public: /// Accessor to \ref gdcmElementSet::tagHT inline TagDocEntryHT &GetEntry(void) { return tagHT; }; - /// Accessor to \ref gdcmDocument::listEntries - //inline ListTag &GetListEntry(void) { return listEntries; }; - /// 'Swap code' accessor (see \ref sw ) inline int GetSwapCode(void) { return sw; } /// File pointer inline FILE * GetFP(void) { return fp; } + bool operator<(gdcmDocument &document); + }; //----------------------------------------------------------------------------- diff --git a/src/gdcmFile.h b/src/gdcmFile.h index 794e2b27..95906988 100644 --- a/src/gdcmFile.h +++ b/src/gdcmFile.h @@ -75,6 +75,11 @@ public: // Body in file gdcmParse.cxx bool ParsePixelData(void); + + inline virtual bool SetEntryByNumber(std::string content, + guint16 group, guint16 element) + { GetHeader()->SetEntryByNumber(content,group,element); } + protected: bool WriteBase(std::string FileName, FileType type); @@ -101,7 +106,9 @@ private: /// \brief Header to use to load the file gdcmHeader *Header; - /// \brief Oops ! Eric : help me + /// \brief Whether the underlying \ref gdcmHeader was loaded by + /// the constructor or passed to the constructor. When false + /// the destructor is in charge of deletion. bool SelfHeader; /// \brief to hold the Pixels (when read) diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index 553997c5..b8b91119 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -112,153 +112,6 @@ bool gdcmHeader::IsReadable(void) { } /** - * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a JPEGBaseLineProcess1 one. - * @return True when JPEGBaseLineProcess1found. False in all other cases. - */ -bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) { - gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadDocEntrySafe(Element); - - std::string Transfer = ((gdcmValEntry *)Element)->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.4.50" ) - return true; - return false; -} - -/** - * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a JPEGExtendedProcess2-4 one. - * @return True when JPEGExtendedProcess2-4 found. False in all other cases. - */ -bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) { - gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadDocEntrySafe(Element); - return ( ((gdcmValEntry *)Element)->GetValue() == "1.2.840.10008.1.2.4.51" ); -} - -/** - * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a JPEGExtendeProcess3-5 one. - * @return True when JPEGExtendedProcess3-5 found. False in all other cases. - */ -bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) { - gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadDocEntrySafe(Element); - - std::string Transfer = ((gdcmValEntry *)Element)->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.4.52" ) - return true; - return false; -} - -/** - * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a JPEGSpectralSelectionProcess6-8 one. - * @return True when JPEGSpectralSelectionProcess6-8 found. False in all - * other cases. - */ -bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) { - gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadDocEntrySafe(Element); - - std::string Transfer = ((gdcmValEntry *)Element)->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.4.53" ) - return true; - return false; -} - -/** - * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a RLE Lossless one. - * @return True when RLE Lossless found. False in all - * other cases. - */ -bool gdcmHeader::IsRLELossLessTransferSyntax(void) { - gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadDocEntrySafe(Element); - - std::string Transfer = ((gdcmValEntry *)Element)->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.5" ) { - return true; - } - return false; -} - -/** - * \ingroup gdcmHeader - * \brief Determines if Transfer Syntax was already encountered - * and if it corresponds to a JPEG Lossless one. - * @return True when RLE Lossless found. False in all - * other cases. - */ -bool gdcmHeader::IsJPEGLossless(void) { - gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); - // faire qq chose d'intelligent a la place de ça - if ( !Element ) - return false; - LoadDocEntrySafe(Element); - - const char * Transfert = ((gdcmValEntry *)Element)->GetValue().c_str(); - - if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true; - if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true; - - if (((gdcmValEntry *)Element)->GetValue() == "1.2.840.10008.1.2.4.57") return true; - - return false; -} - -/** - * \ingroup gdcmHeader - * \brief Determines if the Transfer Syntax was already encountered - * and if it corresponds to a JPEG2000 one - * @return True when JPEG2000 (Lossly or LossLess) found. False in all - * other cases. - */ -bool gdcmHeader::IsJPEG2000(void) { - gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010); - if ( !Element ) - return false; - LoadDocEntrySafe(Element); - - std::string Transfer = ((gdcmValEntry *)Element)->GetValue(); - if ( (Transfer == "1.2.840.10008.1.2.4.90") - || (Transfer == "1.2.840.10008.1.2.4.91") ) - return true; - return false; -} - -/** - * \ingroup gdcmHeader - * \brief Predicate for dicom version 3 file. - * @return True when the file is a dicom version 3. - */ -bool gdcmHeader::IsDicomV3(void) { - // Checking if Transfert Syntax exists is enough - // Anyway, it's to late check if the 'Preamble' was found ... - // And ... would it be a rich idea to check ? - // (some 'no Preamble' DICOM images exist !) - return (GetDocEntryByNumber(0x0002, 0x0010) != NULL); -} - -/** - * \ingroup gdcmHeader * \brief Retrieve the number of columns of image. * @return The encountered size when found, 0 by default. * 0 means the file is NOT USABLE. The caller will have to check @@ -674,27 +527,26 @@ unsigned char * gdcmHeader::GetLUTRGBA(void) { } /** - * \ingroup gdcmHeader - * \brief gets the info from 0002,0010 : Transfert Syntax and gdcmTS + * \brief Accesses the info from 0002,0010 : Transfert Syntax and gdcmTS * else 1. - * @return the full Transfert Syntax Name (as oposite to Transfert Syntax UID) + * @return The full Transfert Syntax Name (as opposed to Transfert Syntax UID) */ std::string gdcmHeader::GetTransfertSyntaxName(void) { // use the gdcmTS (TS : Transfert Syntax) std::string TransfertSyntax = GetEntryByNumber(0x0002,0x0010); if (TransfertSyntax == GDCM_UNFOUND) { - dbg.Verbose(0, "gdcmHeader::GetTransfertSyntaxName: unfound Transfert Syntax (0002,0010)"); + dbg.Verbose(0, "gdcmHeader::GetTransfertSyntaxName:" + " unfound Transfert Syntax (0002,0010)"); return "Uncompressed ACR-NEMA"; } // we do it only when we need it gdcmTS * ts = gdcmGlobal::GetTS(); std::string tsName=ts->GetValue(TransfertSyntax); - //delete ts; // Seg Fault when deleted ?! + //delete ts; /// \todo Seg Fault when deleted ?! return tsName; } /** - * \ingroup gdcmHeader * \brief Sets the Pixel Area size in the Header * --> not-for-rats function * @param ImageDataSize new Pixel Area Size @@ -704,8 +556,6 @@ void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { std::string content1; char car[20]; - // Assumes DocEntry (GrPixel, NumPixel) is unique ... - //\todo deal with multiplicity (see gdcmData/icone.dcm) sprintf(car,"%d",ImageDataSize); gdcmDocEntry *a = GetDocEntryByNumber(GrPixel, NumPixel); @@ -717,96 +567,16 @@ void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { SetEntryByNumber(content1, GrPixel, NumPixel); } - -/** - * \ingroup gdcmHeader - * \brief compares 2 Headers, according to DICOMDIR rules - * --> not-for-rats function - * \warning does NOT work with ACR-NEMA files - * \todo find a trick to solve the pb (use RET fields ?) - * @param header - * @return true if 'smaller' - */ - bool gdcmHeader::operator<(gdcmHeader &header){ - std::string s1,s2; - - // Patient Name - s1=this->GetEntryByNumber(0x0010,0x0010); - s2=header.GetEntryByNumber(0x0010,0x0010); - if(s1 < s2) - return(true); - else if(s1 > s2) - return(false); - else - { - // Patient ID - s1=this->GetEntryByNumber(0x0010,0x0020); - s2=header.GetEntryByNumber(0x0010,0x0020); - if (s1 < s2) - return(true); - else if (s1 > s2) - return(1); - else - { - // Study Instance UID - s1=this->GetEntryByNumber(0x0020,0x000d); - s2=header.GetEntryByNumber(0x0020,0x000d); - if (s1 < s2) - return(true); - else if(s1 > s2) - return(false); - else - { - // Serie Instance UID - s1=this->GetEntryByNumber(0x0020,0x000e); - s2=header.GetEntryByNumber(0x0020,0x000e); - if (s1 < s2) - return(true); - else if(s1 > s2) - return(false); - } - } - } - return(false); -} -// Replaced by gdcmDocument::WriteEntry -/* -bool gdcmHeader::WriteEntry(gdcmDocEntry *tag, FILE *_fp,FileType type) -{ -cout << " gdcmHeader::WriteEntry : entree " << endl; - guint32 length = tag->GetLength(); - - // The value of a tag MUST (see the DICOM norm) be an odd number of - // bytes. When this is not the case, pad with an additional byte: - if(length%2==1) - { - // tag->SetValue(tag->GetValue()+"\0"); // to go on compiling - tag->SetLength(tag->GetReadLength()+1); - } - - WriteEntryTagVRLength(tag, _fp, type); - - // Pixels are never loaded in the element ! - // we stop writting when Pixel are processed - // FIX : we loose trailing elements (RAB, right now) - guint16 el = tag->GetElement(); - guint16 group = tag->GetGroup(); - WriteEntryValue(tag, _fp, type); - return true; -} -*/ //----------------------------------------------------------------------------- // Protected /** - * \ingroup gdcmHeader * \brief anonymize a Header (removes Patient's personal info) * (read the code to see which ones ...) */ bool gdcmHeader::anonymizeHeader() { gdcmDocEntry *patientNameHE = GetDocEntryByNumber (0x0010, 0x0010); - // gdcmDocEntry *patientIDHE = GetDocEntryByNumber (0x0010, 0x0020); ReplaceIfExistByNumber (" ",0x0010, 0x2154); // Telephone ReplaceIfExistByNumber (" ",0x0010, 0x1040); // Adress diff --git a/src/gdcmHeader.h b/src/gdcmHeader.h index 17052f4e..ad4881ff 100644 --- a/src/gdcmHeader.h +++ b/src/gdcmHeader.h @@ -53,14 +53,6 @@ public: // Standard values and informations contained in the header virtual bool IsReadable(void); - bool IsJPEGBaseLineProcess1TransferSyntax(void); - bool IsJPEGExtendedProcess2_4TransferSyntax(void); - bool IsJPEGExtendedProcess3_5TransferSyntax(void); - bool IsJPEGSpectralSelectionProcess6_8TransferSyntax(void); - bool IsRLELossLessTransferSyntax(void); - bool IsJPEGLossless(void); - bool IsJPEG2000(void); - bool IsDicomV3(void); // Some heuristic based accessors, end user intended // (to be moved to gdcmHeaderHelper?) @@ -83,66 +75,16 @@ public: std::string GetTransfertSyntaxName(void); - // When some proprietary shadow groups are disclosed, we can set up - // an additional specific dictionary to access extra information. - - // OK : we still have *ONE* HeaderEntrySet, - // with both Public and Shadow Elements - // parsed against THE Public Dictionary and A (single) Shadow Dictionary - - // TODO Swig int SetShaDict(std::string filename); - // TODO Swig int SetPubDict(std::string filename); - /// Accessor to \ref gdcmHeader::GrPixel guint16 GetGrPixel(void) {return GrPixel;} /// Accessor to \ref gdcmHeader::NumPixel guint16 GetNumPixel(void) {return NumPixel;} -// Entry - -// These functions are necessary for Python because -// there are protected in the parent class - - inline virtual std::string GetEntryByNumber (guint16 group, guint16 element) - { return(gdcmDocument::GetEntryByNumber(group,element)); } - - inline virtual std::string GetEntryVRByNumber(guint16 group, guint16 element) - { return(gdcmDocument::GetEntryVRByNumber(group,element)); } - - inline virtual int GetEntryLengthByNumber(guint16 group, guint16 element) - { return(gdcmDocument::GetEntryLengthByNumber(group,element)); } - - inline virtual std::string GetEntryByName (std::string tagName) - { return(gdcmDocument::GetEntryByName(tagName)); } - - inline virtual std::string GetEntryVRByName (std::string tagName) - { return(gdcmDocument::GetEntryVRByName(tagName)); } - - inline virtual bool SetEntryByNumber(std::string content, - guint16 group, guint16 element) - { return(gdcmDocument::SetEntryByNumber(content,group,element)); } - - inline virtual bool SetEntryByName(std::string content,std::string tagName) - { return(gdcmDocument::SetEntryByName(content,tagName)); } - - inline virtual bool SetEntryLengthByNumber(guint32 l, - guint16 group, guint16 element) - { return(gdcmDocument::SetEntryLengthByNumber(l,group,element)); } - - inline virtual void UpdateShaEntries(void) - { gdcmDocument::UpdateShaEntries(); } - /// Read (used in gdcmFile) void SetImageDataSize(size_t ExpectedSize); - bool operator<(gdcmHeader &header); - -// bool WriteEntry(gdcmDocEntry *tag,FILE *_fp,FileType type); - protected: - //CLEANME int write(std::ostream&); - //CLEANME int anonymize(std::ostream&);//FIXME: anonymize should be a friend bool anonymizeHeader(void); private: -- 2.45.1