From: regrain Date: Wed, 2 Feb 2005 16:18:48 +0000 (+0000) Subject: * Reorder source code X-Git-Tag: Version1.0.bp~106 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=5b89bede4607999aeb8d5b45311e7ee82f9471ef;p=gdcm.git * Reorder source code -- BeNours --- diff --git a/src/gdcmBinEntry.h b/src/gdcmBinEntry.h index f7fa6485..1901cdaa 100644 --- a/src/gdcmBinEntry.h +++ b/src/gdcmBinEntry.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmBinEntry.h,v $ Language: C++ - Date: $Date: 2005/01/30 17:30:57 $ - Version: $Revision: 1.35 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.36 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -50,8 +50,8 @@ public: /// \brief Returns the area value of the current Dicom Entry /// when it's not string-translatable (e.g : LUT table, overlay, icon) uint8_t *GetBinArea() { return BinArea; } - void SetBinArea( uint8_t *area, bool self = true ); + /// \brief Sets SelfArea void SetSelfArea(bool area) { SelfArea = area; }; /// \brief Returns SelfArea diff --git a/src/gdcmContentEntry.h b/src/gdcmContentEntry.h index 8cb66a0a..2fb858c5 100644 --- a/src/gdcmContentEntry.h +++ b/src/gdcmContentEntry.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmContentEntry.h,v $ Language: C++ - Date: $Date: 2005/01/30 17:30:57 $ - Version: $Revision: 1.4 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.5 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -39,11 +39,8 @@ class GDCM_EXPORT ContentEntry : public DocEntry public: virtual void WriteContent(std::ofstream *fp, FileType filetype) = 0; - // Accessors are protected, not to be invoked by end user - /// Sets the value (string) of the current Dicom entry virtual void SetValue(std::string const &val) { Value = val; }; - /// \brief Returns the 'Value' (e.g. "Dupond Marcel") converted /// into a 'string', event if it's physically stored on disk as an integer std::string const &GetValue() const { return Value; }; diff --git a/src/gdcmDocEntry.cxx b/src/gdcmDocEntry.cxx index 3e218c41..474d5681 100644 --- a/src/gdcmDocEntry.cxx +++ b/src/gdcmDocEntry.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocEntry.cxx,v $ Language: C++ - Date: $Date: 2005/02/02 10:02:17 $ - Version: $Revision: 1.51 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.52 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -168,18 +168,6 @@ uint32_t DocEntry::GetFullLength() return l; } -/** - * \brief Copies all the attributes from an other DocEntry - * @param doc entry to copy from - */ -void DocEntry::Copy(DocEntry *doc) -{ - Length = doc->Length; - ReadLength = doc->ReadLength; - ImplicitVR = doc->ImplicitVR; - Offset = doc->Offset; -} - /** * \brief tells us if entry is the last one of a 'no length' SequenceItem * (fffe,e00d) @@ -198,6 +186,18 @@ bool DocEntry::IsSequenceDelimitor() return (GetGroup() == 0xfffe && GetElement() == 0xe0dd); } +/** + * \brief Copies all the attributes from an other DocEntry + * @param doc entry to copy from + */ +void DocEntry::Copy(DocEntry *doc) +{ + Length = doc->Length; + ReadLength = doc->ReadLength; + ImplicitVR = doc->ImplicitVR; + Offset = doc->Offset; +} + //----------------------------------------------------------------------------- // Protected diff --git a/src/gdcmDocEntry.h b/src/gdcmDocEntry.h index a76778b6..b77f2943 100644 --- a/src/gdcmDocEntry.h +++ b/src/gdcmDocEntry.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocEntry.h,v $ Language: C++ - Date: $Date: 2005/01/31 12:19:33 $ - Version: $Revision: 1.44 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.45 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -44,6 +44,11 @@ public: virtual ~DocEntry() {}; virtual void Print (std::ostream &os = std::cout, std::string const &indent = ""); + virtual void WriteContent(std::ofstream *fp, FileType filetype); + + /// \brief Gets the DicEntry of the current Dicom entry + /// @return The DicEntry of the current Dicom entry + DictEntry * GetDictEntry() { return DicomDict; }; /// Returns the Dicom Group number of the current Dicom entry uint16_t GetGroup() { return DicomDict->GetGroup(); }; @@ -51,9 +56,8 @@ public: /// Returns the Dicom Element number of the current Dicom entry uint16_t GetElement() { return DicomDict->GetElement();}; - /// Returns the 'key' of the current Dicom entry + /// Set the 'key' of the current Dicom entry void SetKey( TagKey const &key ) { Key = key; } - /// Returns the 'key' of the current Dicom entry std::string const &GetKey() const { return Key; } @@ -82,7 +86,6 @@ public: /// \brief Sets only 'Read Length' (*not* 'Usable Length') of the current /// Dicom entry void SetReadLength(uint32_t l) { ReadLength = l; }; - /// \brief Returns the 'read length' of the current Dicom entry /// \warning this value is the one stored in the Dicom header but not /// mandatoryly the one thats's used (in case on SQ, or delimiters, @@ -92,15 +95,14 @@ public: /// \brief Sets both 'Read Length' and 'Usable Length' of the current /// Dicom entry void SetLength(uint32_t l) { Length = l; }; - /// \brief Returns the actual value length of the current Dicom entry /// \warning this value is not *always* the one stored in the Dicom header /// in case of well knowned bugs uint32_t GetLength() { return Length; }; - - // The following 3 members, for internal use only ! - + uint32_t GetFullLength(); + +// The following 3 members, for internal use only ! /// \brief Sets the offset of the Dicom entry /// \warning use with caution ! /// @param of offset to be set @@ -121,18 +123,10 @@ public: /// @return true if the VM is unknown bool IsVMUnknown() { return DicomDict->IsVMUnknown(); }; - /// \brief Gets the DicEntry of the current Dicom entry - /// @return The DicEntry of the current Dicom entry - DictEntry * GetDictEntry() { return DicomDict; }; - - virtual void WriteContent(std::ofstream *fp, FileType filetype); - - uint32_t GetFullLength(); - - virtual void Copy(DocEntry *e); - bool IsItemDelimitor(); bool IsSequenceDelimitor(); + + virtual void Copy(DocEntry *e); protected: /// \brief pointer to the underlying Dicom dictionary element diff --git a/src/gdcmDocEntrySet.cxx b/src/gdcmDocEntrySet.cxx index 9f4d7c42..6a4597f0 100644 --- a/src/gdcmDocEntrySet.cxx +++ b/src/gdcmDocEntrySet.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocEntrySet.cxx,v $ Language: C++ - Date: $Date: 2005/02/02 10:02:17 $ - Version: $Revision: 1.51 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.52 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -431,22 +431,6 @@ bool DocEntrySet::CheckIfEntryExist(uint16_t group, uint16_t elem ) return GetDocEntry(group,elem)!=NULL; } -/** - * \brief Request a new virtual dict entry to the dict set - * @param group group number of the underlying DictEntry - * @param elem element number of the underlying DictEntry - * @param vr VR (Value Representation) of the underlying DictEntry - * @param vm VM (Value Multiplicity) of the underlying DictEntry - * @param name english name - */ -DictEntry* DocEntrySet::NewVirtualDictEntry( uint16_t group,uint16_t elem, - TagName const & vr, - TagName const & vm, - TagName const & name ) -{ - return Global::GetDicts()->NewVirtualDictEntry(group,elem,vr,vm,name); -} - /** * \brief Build a new Val Entry from all the low level arguments. * Check for existence of dictionary entry, and build @@ -515,6 +499,22 @@ SeqEntry* DocEntrySet::NewSeqEntry(uint16_t group, uint16_t elem) return newEntry; } +/** + * \brief Request a new virtual dict entry to the dict set + * @param group group number of the underlying DictEntry + * @param elem element number of the underlying DictEntry + * @param vr VR (Value Representation) of the underlying DictEntry + * @param vm VM (Value Multiplicity) of the underlying DictEntry + * @param name english name + */ +DictEntry* DocEntrySet::NewVirtualDictEntry( uint16_t group,uint16_t elem, + TagName const & vr, + TagName const & vm, + TagName const & name ) +{ + return Global::GetDicts()->NewVirtualDictEntry(group,elem,vr,vm,name); +} + //----------------------------------------------------------------------------- // Protected /** diff --git a/src/gdcmDocEntrySet.h b/src/gdcmDocEntrySet.h index 7ac500c8..c1374a1b 100644 --- a/src/gdcmDocEntrySet.h +++ b/src/gdcmDocEntrySet.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocEntrySet.h,v $ Language: C++ - Date: $Date: 2005/02/02 14:26:34 $ - Version: $Revision: 1.46 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.47 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -24,6 +24,7 @@ namespace gdcm { +//----------------------------------------------------------------------------- class DocEntry; class ValEntry; class BinEntry; @@ -31,8 +32,8 @@ class SeqEntry; class DictEntry; typedef std::string BaseTagKey; -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- /** * \brief * \ref DocEntrySet is an abstract base class for \ref ElementSet @@ -108,11 +109,6 @@ public: virtual bool IsEmpty() = 0; virtual bool CheckIfEntryExist(uint16_t group, uint16_t elem); - DictEntry *NewVirtualDictEntry(uint16_t group,uint16_t elem, - TagName const &vr = GDCM_UNKNOWN, - TagName const &vm = GDCM_UNKNOWN, - TagName const &name = GDCM_UNKNOWN ); - // DocEntry related utilities ValEntry *NewValEntry(uint16_t group,uint16_t elem, TagName const &vr = GDCM_UNKNOWN); @@ -120,6 +116,12 @@ public: TagName const &vr = GDCM_UNKNOWN); SeqEntry *NewSeqEntry(uint16_t group, uint16_t elem); +// DictEntry related utilities + DictEntry *NewVirtualDictEntry(uint16_t group,uint16_t elem, + TagName const &vr = GDCM_UNKNOWN, + TagName const &vm = GDCM_UNKNOWN, + TagName const &name = GDCM_UNKNOWN ); + protected: // DictEntry related utilities DictEntry *GetDictEntry(uint16_t group, uint16_t elem); diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index 0f76b64a..8c0ddc3c 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.cxx,v $ Language: C++ - Date: $Date: 2005/02/02 10:02:17 $ - Version: $Revision: 1.219 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.220 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -496,18 +496,18 @@ void Document::WriteContent(std::ofstream *fp, FileType filetype) fp->write("DICM", 4); } -/* - * \todo rewrite later, if really usefull - * - 'Group Length' element is optional in DICOM - * - but un-updated odd groups lengthes can causes pb - * (xmedcon breaker) - * - * if ( (filetype == ImplicitVR) || (filetype == ExplicitVR) ) - * UpdateGroupLength(false,filetype); - * if ( filetype == ACR) - * UpdateGroupLength(true,ACR); - */ - + /* + * \todo rewrite later, if really usefull + * - 'Group Length' element is optional in DICOM + * - but un-updated odd groups lengthes can causes pb + * (xmedcon breaker) + * + * if ( (filetype == ImplicitVR) || (filetype == ExplicitVR) ) + * UpdateGroupLength(false,filetype); + * if ( filetype == ACR) + * UpdateGroupLength(true,ACR); + */ + ElementSet::WriteContent(fp, filetype); // This one is recursive } @@ -589,6 +589,71 @@ void Document::LoadDocEntrySafe(DocEntry *entry) } } +/** + * \brief Compares two documents, according to \ref DicomDir 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 Document::operator<(Document &document) +{ + // Patient Name + std::string s1 = GetEntryValue(0x0010,0x0010); + std::string s2 = document.GetEntryValue(0x0010,0x0010); + if(s1 < s2) + { + return true; + } + else if( s1 > s2 ) + { + return false; + } + else + { + // Patient ID + s1 = GetEntryValue(0x0010,0x0020); + s2 = document.GetEntryValue(0x0010,0x0020); + if ( s1 < s2 ) + { + return true; + } + else if ( s1 > s2 ) + { + return false; + } + else + { + // Study Instance UID + s1 = GetEntryValue(0x0020,0x000d); + s2 = document.GetEntryValue(0x0020,0x000d); + if ( s1 < s2 ) + { + return true; + } + else if( s1 > s2 ) + { + return false; + } + else + { + // Serie Instance UID + s1 = GetEntryValue(0x0020,0x000e); + s2 = document.GetEntryValue(0x0020,0x000e); + if ( s1 < s2 ) + { + return true; + } + else if( s1 > s2 ) + { + return false; + } + } + } + } + return false; +} + //----------------------------------------------------------------------------- // Protected /** @@ -693,6 +758,17 @@ int Document::ComputeGroup0002Length( FileType filetype ) //----------------------------------------------------------------------------- // Private +/** + * \brief Loads all the needed Dictionaries + * \warning NOT end user intended method ! + */ +void Document::Initialize() +{ + RefPubDict = Global::GetDicts()->GetDefaultPubDict(); + RefShaDict = NULL; + Filetype = Unknown; +} + /** * \brief Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries) * @return length of the parsed set. @@ -1363,9 +1439,6 @@ std::string Document::FindDocEntryVR() */ bool Document::CheckDocEntryVR(VRKey vr) { - // CLEANME searching the dicom_vr at each occurence is expensive. - // PostPone this test in an optional integrity check at the end - // of parsing or only in debug mode. if ( !Global::GetVR()->IsValidVR(vr) ) return false; @@ -1642,17 +1715,6 @@ bool Document::IsDocEntryAnInteger(DocEntry *entry) return false; } -/** - * \brief Loads all the needed Dictionaries - * \warning NOT end user intended method ! - */ -void Document::Initialize() -{ - RefPubDict = Global::GetDicts()->GetDefaultPubDict(); - RefShaDict = NULL; - Filetype = Unknown; -} - /** * \brief Discover what the swap code is (among little endian, big endian, * bad little endian, bad big endian). @@ -2051,94 +2113,8 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem) } } -/** - * \brief Compares two documents, according to \ref DicomDir 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 Document::operator<(Document &document) -{ - // Patient Name - std::string s1 = GetEntryValue(0x0010,0x0010); - std::string s2 = document.GetEntryValue(0x0010,0x0010); - if(s1 < s2) - { - return true; - } - else if( s1 > s2 ) - { - return false; - } - else - { - // Patient ID - s1 = GetEntryValue(0x0010,0x0020); - s2 = document.GetEntryValue(0x0010,0x0020); - if ( s1 < s2 ) - { - return true; - } - else if ( s1 > s2 ) - { - return false; - } - else - { - // Study Instance UID - s1 = GetEntryValue(0x0020,0x000d); - s2 = document.GetEntryValue(0x0020,0x000d); - if ( s1 < s2 ) - { - return true; - } - else if( s1 > s2 ) - { - return false; - } - else - { - // Serie Instance UID - s1 = GetEntryValue(0x0020,0x000e); - s2 = document.GetEntryValue(0x0020,0x000e); - if ( s1 < s2 ) - { - return true; - } - else if( s1 > s2 ) - { - return false; - } - } - } - } - return false; -} - //----------------------------------------------------------------------------- // Print -/** - * \brief Prints The Dict Entries of THE public Dicom Dictionary - * @param os ostream to print to - * @return - */ -void Document::PrintPubDict(std::ostream &os) -{ - RefPubDict->SetPrintLevel(PrintLevel); - RefPubDict->Print(os); -} - -/** - * \brief Prints The Dict Entries of THE shadow Dicom Dictionary - * @param os ostream to print to - * @return - */ -void Document::PrintShaDict(std::ostream &os) -{ - RefShaDict->SetPrintLevel(PrintLevel); - RefShaDict->Print(os); -} //----------------------------------------------------------------------------- } // end namespace gdcm diff --git a/src/gdcmDocument.h b/src/gdcmDocument.h index c51a7d5d..727d049d 100644 --- a/src/gdcmDocument.h +++ b/src/gdcmDocument.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.h,v $ Language: C++ - Date: $Date: 2005/01/31 12:19:34 $ - Version: $Revision: 1.103 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.104 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -44,9 +44,6 @@ class GDCM_EXPORT Document : public ElementSet public: // Dictionaries - virtual void PrintPubDict (std::ostream &os = std::cout); - virtual void PrintShaDict (std::ostream &os = std::cout); - Dict* GetPubDict(); Dict* GetShaDict(); bool SetShaDict(Dict* dict); @@ -74,9 +71,6 @@ public: /// so they agree with the processor order. uint32_t UnswapLong(uint32_t a) { return SwapLong(a);} -// Ordering of Documents - bool operator<(Document &document); - // File I/O /// Accessor to \ref Filename const std::string &GetFileName() const { return Filename; } @@ -88,12 +82,14 @@ public: void WriteContent( std::ofstream *fp, FileType type ); // Content entries - virtual void LoadEntryBinArea(uint16_t group, uint16_t elem); virtual void LoadEntryBinArea(BinEntry *entry); void LoadDocEntrySafe(DocEntry *entry); +// Ordering of Documents + bool operator<(Document &document); + protected: // Methods // Constructor and destructor are protected to forbid end user @@ -149,6 +145,8 @@ protected: private: // Methods + void Initialize(); + // Read void ParseDES(DocEntrySet *set,long offset, long l_max, bool delim_mode); void ParseSQ (SeqEntry *seq, long offset, long l_max, bool delim_mode); @@ -168,7 +166,6 @@ private: void FixDocEntryFoundLength(DocEntry *entry,uint32_t l); bool IsDocEntryAnInteger (DocEntry *entry); - void Initialize(); bool CheckSwap(); void SwitchByteSwapCode(); void SetMaxSizeLoadEntry(long); diff --git a/src/gdcmElementSet.cxx b/src/gdcmElementSet.cxx index 510ac747..1330a42f 100644 --- a/src/gdcmElementSet.cxx +++ b/src/gdcmElementSet.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmElementSet.cxx,v $ Language: C++ - Date: $Date: 2005/02/01 10:29:55 $ - Version: $Revision: 1.52 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.53 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -62,21 +62,6 @@ void ElementSet::WriteContent(std::ofstream *fp, FileType filetype) } } -/** - * \brief delete all entries in the ElementSet - */ -void ElementSet::ClearEntry() -{ - for(TagDocEntryHT::iterator cc = TagHT.begin();cc != TagHT.end(); ++cc) - { - if ( cc->second ) - { - delete cc->second; - } - } - TagHT.clear(); -} - /** * \brief add a new Dicom Element pointer to the H Table * @param newEntry entry to add @@ -134,6 +119,21 @@ bool ElementSet::RemoveEntryNoDestroy(DocEntry *entryToRemove) return false ; } +/** + * \brief delete all entries in the ElementSet + */ +void ElementSet::ClearEntry() +{ + for(TagDocEntryHT::iterator cc = TagHT.begin();cc != TagHT.end(); ++cc) + { + if ( cc->second ) + { + delete cc->second; + } + } + TagHT.clear(); +} + /** * \brief Get the first entry while visiting the DocEntrySet * \return The first DocEntry if found, otherwhise NULL diff --git a/src/gdcmElementSet.h b/src/gdcmElementSet.h index aa2995ba..dcf695ad 100644 --- a/src/gdcmElementSet.h +++ b/src/gdcmElementSet.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmElementSet.h,v $ Language: C++ - Date: $Date: 2005/01/26 11:42:02 $ - Version: $Revision: 1.40 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.41 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -51,10 +51,10 @@ public: void WriteContent(std::ofstream *fp, FileType filetype); - void ClearEntry(); bool AddEntry(DocEntry *Entry); bool RemoveEntry(DocEntry *EntryToRemove); bool RemoveEntryNoDestroy(DocEntry *EntryToRemove); + void ClearEntry(); DocEntry *GetFirstEntry(); DocEntry *GetNextEntry(); diff --git a/src/gdcmFile.cxx b/src/gdcmFile.cxx index 0b31c5ce..cc5ff672 100644 --- a/src/gdcmFile.cxx +++ b/src/gdcmFile.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmFile.cxx,v $ Language: C++ - Date: $Date: 2005/02/02 10:02:17 $ - Version: $Revision: 1.207 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.208 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -16,6 +16,18 @@ =========================================================================*/ +// +// -------------- Remember ! ---------------------------------- +// +// Image Position Patient (0020,0032): +// If not found (ACR_NEMA) we try Image Position (0020,0030) +// If not found (ACR-NEMA), we consider Slice Location (0020,1041) +// or Location (0020,0050) +// as the Z coordinate, +// 0. for all the coordinates if nothing is found +// +// --------------------------------------------------------------- +// #include "gdcmFile.h" #include "gdcmGlobal.h" #include "gdcmUtil.h" @@ -157,130 +169,6 @@ File::~File () //----------------------------------------------------------------------------- // Public -/** - * \brief Performs some consistency checking on various 'File related' - * (as opposed to 'DicomDir related') entries - * then writes in a file all the (Dicom Elements) included the Pixels - * @param fileName file name to write to - * @param filetype Type of the File to be written - * (ACR, ExplicitVR, ImplicitVR) - */ -bool File::Write(std::string fileName, FileType filetype) -{ - std::ofstream *fp = new std::ofstream(fileName.c_str(), - std::ios::out | std::ios::binary); - if (*fp == NULL) - { - gdcmVerboseMacro("Failed to open (write) File: " << fileName.c_str()); - return false; - } - - // Entry : 0002|0000 = group length -> recalculated - ValEntry *e0002 = GetValEntry(0x0002,0x0000); - if( e0002 ) - { - std::ostringstream sLen; - sLen << ComputeGroup0002Length(filetype); - e0002->SetValue(sLen.str()); - } - - // Bits Allocated - if ( GetEntryValue(0x0028,0x0100) == "12") - { - SetValEntry("16", 0x0028,0x0100); - } - - int i_lgPix = GetEntryLength(GrPixel, NumPixel); - if (i_lgPix != -2) - { - // no (GrPixel, NumPixel) element - std::string s_lgPix = Util::Format("%d", i_lgPix+12); - s_lgPix = Util::DicomString( s_lgPix.c_str() ); - InsertValEntry(s_lgPix,GrPixel, 0x0000); - } - - // FIXME : should be nice if we could move it to File - // (or in future gdcmPixelData class) - - // Drop Palette Color, if necessary - if ( GetEntryValue(0x0028,0x0002).c_str()[0] == '3' ) - { - // if SamplesPerPixel = 3, sure we don't need any LUT ! - // Drop 0028|1101, 0028|1102, 0028|1103 - // Drop 0028|1201, 0028|1202, 0028|1203 - - DocEntry *e = GetDocEntry(0x0028,0x01101); - if (e) - { - RemoveEntryNoDestroy(e); - } - e = GetDocEntry(0x0028,0x1102); - if (e) - { - RemoveEntryNoDestroy(e); - } - e = GetDocEntry(0x0028,0x1103); - if (e) - { - RemoveEntryNoDestroy(e); - } - e = GetDocEntry(0x0028,0x01201); - if (e) - { - RemoveEntryNoDestroy(e); - } - e = GetDocEntry(0x0028,0x1202); - if (e) - { - RemoveEntryNoDestroy(e); - } - e = GetDocEntry(0x0028,0x1203); - if (e) - { - RemoveEntryNoDestroy(e); - } - } - -/* -#ifdef GDCM_WORDS_BIGENDIAN - // Super Super hack that will make gdcm a BOMB ! but should - // Fix temporarily the dashboard - BinEntry *b = GetBinEntry(GrPixel,NumPixel); - if ( GetPixelSize() == 16 ) - { - uint16_t *im16 = (uint16_t *)b->GetBinArea(); - int lgr = b->GetLength(); - for( int i = 0; i < lgr / 2; i++ ) - { - im16[i]= (im16[i] >> 8) | (im16[i] << 8 ); - } - } -#endif //GDCM_WORDS_BIGENDIAN -*/ - - Document::WriteContent(fp, filetype); - -/* -#ifdef GDCM_WORDS_BIGENDIAN - // Flip back the pixel ... I told you this is a hack - if ( GetPixelSize() == 16 ) - { - uint16_t *im16 = (uint16_t*)b->GetBinArea(); - int lgr = b->GetLength(); - for( int i = 0; i < lgr / 2; i++ ) - { - im16[i]= (im16[i] >> 8) | (im16[i] << 8 ); - } - } -#endif //GDCM_WORDS_BIGENDIAN -*/ - - fp->close(); - delete fp; - - return true; -} - /** * \brief This predicate, based on hopefully reasonable heuristics, * decides whether or not the current File was properly parsed @@ -321,6 +209,89 @@ bool File::IsReadable() return true; } +/** + * \brief gets the info from 0020,0013 : Image Number else 0. + * @return image number + */ +int File::GetImageNumber() +{ + // The function i atoi() takes the address of an area of memory as + // parameter and converts the string stored at that location to an integer + // using the external decimal to internal binary conversion rules. This may + // be preferable to sscanf() since atoi() is a much smaller, simpler and + // faster function. sscanf() can do all possible conversions whereas + // atoi() can only do single decimal integer conversions. + //0020 0013 IS REL Image Number + std::string strImNumber = GetEntryValue(0x0020,0x0013); + if ( strImNumber != GDCM_UNFOUND ) + { + return atoi( strImNumber.c_str() ); + } + return 0; //Hopeless +} + +/** + * \brief gets the info from 0008,0060 : Modality + * @return Modality Type + */ +ModalityType File::GetModality() +{ + // 0008 0060 CS ID Modality + std::string strModality = GetEntryValue(0x0008,0x0060); + if ( strModality != GDCM_UNFOUND ) + { + if ( strModality.find("AU") < strModality.length()) return AU; + else if ( strModality.find("AS") < strModality.length()) return AS; + else if ( strModality.find("BI") < strModality.length()) return BI; + else if ( strModality.find("CF") < strModality.length()) return CF; + else if ( strModality.find("CP") < strModality.length()) return CP; + else if ( strModality.find("CR") < strModality.length()) return CR; + else if ( strModality.find("CT") < strModality.length()) return CT; + else if ( strModality.find("CS") < strModality.length()) return CS; + else if ( strModality.find("DD") < strModality.length()) return DD; + else if ( strModality.find("DF") < strModality.length()) return DF; + else if ( strModality.find("DG") < strModality.length()) return DG; + else if ( strModality.find("DM") < strModality.length()) return DM; + else if ( strModality.find("DS") < strModality.length()) return DS; + else if ( strModality.find("DX") < strModality.length()) return DX; + else if ( strModality.find("ECG") < strModality.length()) return ECG; + else if ( strModality.find("EPS") < strModality.length()) return EPS; + else if ( strModality.find("FA") < strModality.length()) return FA; + else if ( strModality.find("FS") < strModality.length()) return FS; + else if ( strModality.find("HC") < strModality.length()) return HC; + else if ( strModality.find("HD") < strModality.length()) return HD; + else if ( strModality.find("LP") < strModality.length()) return LP; + else if ( strModality.find("LS") < strModality.length()) return LS; + else if ( strModality.find("MA") < strModality.length()) return MA; + else if ( strModality.find("MR") < strModality.length()) return MR; + else if ( strModality.find("NM") < strModality.length()) return NM; + else if ( strModality.find("OT") < strModality.length()) return OT; + else if ( strModality.find("PT") < strModality.length()) return PT; + else if ( strModality.find("RF") < strModality.length()) return RF; + else if ( strModality.find("RG") < strModality.length()) return RG; + else if ( strModality.find("RTDOSE") < strModality.length()) return RTDOSE; + else if ( strModality.find("RTIMAGE") < strModality.length()) return RTIMAGE; + else if ( strModality.find("RTPLAN") < strModality.length()) return RTPLAN; + else if ( strModality.find("RTSTRUCT") < strModality.length()) return RTSTRUCT; + else if ( strModality.find("SM") < strModality.length()) return SM; + else if ( strModality.find("ST") < strModality.length()) return ST; + else if ( strModality.find("TG") < strModality.length()) return TG; + else if ( strModality.find("US") < strModality.length()) return US; + else if ( strModality.find("VF") < strModality.length()) return VF; + else if ( strModality.find("XA") < strModality.length()) return XA; + else if ( strModality.find("XC") < strModality.length()) return XC; + + else + { + /// \todo throw error return value ??? + /// specified <> unknown in our database + return Unknow; + } + } + + return Unknow; +} + /** * \brief Retrieve the number of columns of image. * @return The encountered size when found, 0 by default. @@ -504,165 +475,40 @@ float File::GetZSpacing() } /** - *\brief gets the info from 0028,1052 : Rescale Intercept - * @return Rescale Intercept + * \brief gets the info from 0020,0032 : Image Position Patient + * else from 0020,0030 : Image Position (RET) + * else 0. + * @return up-left image corner X position */ -float File::GetRescaleIntercept() +float File::GetXOrigin() { - float resInter = 0.; - /// 0028 1052 DS IMG Rescale Intercept - const std::string &strRescInter = GetEntryValue(0x0028,0x1052); - if ( strRescInter != GDCM_UNFOUND ) + float xImPos, yImPos, zImPos; + std::string strImPos = GetEntryValue(0x0020,0x0032); + + if ( strImPos == GDCM_UNFOUND ) { - if( sscanf( strRescInter.c_str(), "%f", &resInter) != 1 ) + gdcmVerboseMacro( "Unfound Image Position Patient (0020,0032)"); + strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images + if ( strImPos == GDCM_UNFOUND ) { - // bug in the element 0x0028,0x1052 - gdcmVerboseMacro( "Rescale Intercept (0028,1052) is empty." ); + gdcmVerboseMacro( "Unfound Image Position (RET) (0020,0030)"); + return 0.; } } - return resInter; + if( sscanf( strImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3 ) + { + return 0.; + } + + return xImPos; } /** - *\brief gets the info from 0028,1053 : Rescale Slope - * @return Rescale Slope - */ -float File::GetRescaleSlope() -{ - float resSlope = 1.; - //0028 1053 DS IMG Rescale Slope - std::string strRescSlope = GetEntryValue(0x0028,0x1053); - if ( strRescSlope != GDCM_UNFOUND ) - { - if( sscanf( strRescSlope.c_str(), "%f", &resSlope) != 1) - { - // bug in the element 0x0028,0x1053 - gdcmVerboseMacro( "Rescale Slope (0028,1053) is empty."); - } - } - - return resSlope; -} - -/** - * \brief This function is intended to user who doesn't want - * to have to manage a LUT and expects to get an RBG Pixel image - * (or a monochrome one ...) - * \warning to be used with GetImagePixels() - * @return 1 if Gray level, 3 if Color (RGB, YBR or PALETTE COLOR) - */ -int File::GetNumberOfScalarComponents() -{ - if ( GetSamplesPerPixel() == 3 ) - { - return 3; - } - - // 0028 0100 US IMG Bits Allocated - // (in order no to be messed up by old RGB images) - if ( GetEntryValue(0x0028,0x0100) == "24" ) - { - return 3; - } - - std::string strPhotometricInterpretation = GetEntryValue(0x0028,0x0004); - - if ( ( strPhotometricInterpretation == "PALETTE COLOR ") ) - { - if ( HasLUT() )// PALETTE COLOR is NOT enough - { - return 3; - } - else - { - return 1; - } - } - - // beware of trailing space at end of string - // DICOM tags are never of odd length - if ( strPhotometricInterpretation == GDCM_UNFOUND || - Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME1") || - Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME2") ) - { - return 1; - } - else - { - // we assume that *all* kinds of YBR are dealt with - return 3; - } -} - -/** - * \brief This function is intended to user that DOESN'T want - * to get RGB pixels image when it's stored as a PALETTE COLOR image - * - the (vtk) user is supposed to know how deal with LUTs - - * \warning to be used with GetImagePixelsRaw() - * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -) - */ -int File::GetNumberOfScalarComponentsRaw() -{ - // 0028 0100 US IMG Bits Allocated - // (in order no to be messed up by old RGB images) - if ( File::GetEntryValue(0x0028,0x0100) == "24" ) - { - return 3; - } - - // we assume that *all* kinds of YBR are dealt with - return GetSamplesPerPixel(); -} - -// -// -------------- Remember ! ---------------------------------- -// -// Image Position Patient (0020,0032): -// If not found (ACR_NEMA) we try Image Position (0020,0030) -// If not found (ACR-NEMA), we consider Slice Location (0020,1041) -// or Location (0020,0050) -// as the Z coordinate, -// 0. for all the coordinates if nothing is found -// -// --------------------------------------------------------------- -// - -/** - * \brief gets the info from 0020,0032 : Image Position Patient - * else from 0020,0030 : Image Position (RET) - * else 0. - * @return up-left image corner X position - */ -float File::GetXOrigin() -{ - float xImPos, yImPos, zImPos; - std::string strImPos = GetEntryValue(0x0020,0x0032); - - if ( strImPos == GDCM_UNFOUND ) - { - gdcmVerboseMacro( "Unfound Image Position Patient (0020,0032)"); - strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images - if ( strImPos == GDCM_UNFOUND ) - { - gdcmVerboseMacro( "Unfound Image Position (RET) (0020,0030)"); - return 0.; - } - } - - if( sscanf( strImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3 ) - { - return 0.; - } - - return xImPos; -} - -/** - * \brief gets the info from 0020,0032 : Image Position Patient - * else from 0020,0030 : Image Position (RET) - * else 0. - * @return up-left image corner Y position + * \brief gets the info from 0020,0032 : Image Position Patient + * else from 0020,0030 : Image Position (RET) + * else 0. + * @return up-left image corner Y position */ float File::GetYOrigin() { @@ -763,86 +609,36 @@ float File::GetZOrigin() } /** - * \brief gets the info from 0020,0013 : Image Number else 0. - * @return image number - */ -int File::GetImageNumber() + * \brief gets the info from 0020,0037 : Image Orientation Patient + * (needed to organize DICOM files based on their x,y,z position) + * @param iop adress of the (6)float aray to receive values + * @return cosines of image orientation patient + */ +void File::GetImageOrientationPatient( float iop[6] ) { - // The function i atoi() takes the address of an area of memory as - // parameter and converts the string stored at that location to an integer - // using the external decimal to internal binary conversion rules. This may - // be preferable to sscanf() since atoi() is a much smaller, simpler and - // faster function. sscanf() can do all possible conversions whereas - // atoi() can only do single decimal integer conversions. - //0020 0013 IS REL Image Number - std::string strImNumber = GetEntryValue(0x0020,0x0013); - if ( strImNumber != GDCM_UNFOUND ) + std::string strImOriPat; + //iop is supposed to be float[6] + iop[0] = iop[1] = iop[2] = iop[3] = iop[4] = iop[5] = 0.; + + // 0020 0037 DS REL Image Orientation (Patient) + if ( (strImOriPat = GetEntryValue(0x0020,0x0037)) != GDCM_UNFOUND ) { - return atoi( strImNumber.c_str() ); + if( sscanf( strImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", + &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 ) + { + gdcmVerboseMacro( "Wrong Image Orientation Patient (0020,0037). Less than 6 values were found." ); + } } - return 0; //Hopeless -} - -/** - * \brief gets the info from 0008,0060 : Modality - * @return Modality Type - */ -ModalityType File::GetModality() -{ - // 0008 0060 CS ID Modality - std::string strModality = GetEntryValue(0x0008,0x0060); - if ( strModality != GDCM_UNFOUND ) + //For ACR-NEMA + // 0020 0035 DS REL Image Orientation (RET) + else if ( (strImOriPat = GetEntryValue(0x0020,0x0035)) != GDCM_UNFOUND ) { - if ( strModality.find("AU") < strModality.length()) return AU; - else if ( strModality.find("AS") < strModality.length()) return AS; - else if ( strModality.find("BI") < strModality.length()) return BI; - else if ( strModality.find("CF") < strModality.length()) return CF; - else if ( strModality.find("CP") < strModality.length()) return CP; - else if ( strModality.find("CR") < strModality.length()) return CR; - else if ( strModality.find("CT") < strModality.length()) return CT; - else if ( strModality.find("CS") < strModality.length()) return CS; - else if ( strModality.find("DD") < strModality.length()) return DD; - else if ( strModality.find("DF") < strModality.length()) return DF; - else if ( strModality.find("DG") < strModality.length()) return DG; - else if ( strModality.find("DM") < strModality.length()) return DM; - else if ( strModality.find("DS") < strModality.length()) return DS; - else if ( strModality.find("DX") < strModality.length()) return DX; - else if ( strModality.find("ECG") < strModality.length()) return ECG; - else if ( strModality.find("EPS") < strModality.length()) return EPS; - else if ( strModality.find("FA") < strModality.length()) return FA; - else if ( strModality.find("FS") < strModality.length()) return FS; - else if ( strModality.find("HC") < strModality.length()) return HC; - else if ( strModality.find("HD") < strModality.length()) return HD; - else if ( strModality.find("LP") < strModality.length()) return LP; - else if ( strModality.find("LS") < strModality.length()) return LS; - else if ( strModality.find("MA") < strModality.length()) return MA; - else if ( strModality.find("MR") < strModality.length()) return MR; - else if ( strModality.find("NM") < strModality.length()) return NM; - else if ( strModality.find("OT") < strModality.length()) return OT; - else if ( strModality.find("PT") < strModality.length()) return PT; - else if ( strModality.find("RF") < strModality.length()) return RF; - else if ( strModality.find("RG") < strModality.length()) return RG; - else if ( strModality.find("RTDOSE") < strModality.length()) return RTDOSE; - else if ( strModality.find("RTIMAGE") < strModality.length()) return RTIMAGE; - else if ( strModality.find("RTPLAN") < strModality.length()) return RTPLAN; - else if ( strModality.find("RTSTRUCT") < strModality.length()) return RTSTRUCT; - else if ( strModality.find("SM") < strModality.length()) return SM; - else if ( strModality.find("ST") < strModality.length()) return ST; - else if ( strModality.find("TG") < strModality.length()) return TG; - else if ( strModality.find("US") < strModality.length()) return US; - else if ( strModality.find("VF") < strModality.length()) return VF; - else if ( strModality.find("XA") < strModality.length()) return XA; - else if ( strModality.find("XC") < strModality.length()) return XC; - - else + if( sscanf( strImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", + &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 ) { - /// \todo throw error return value ??? - /// specified <> unknown in our database - return Unknow; + gdcmVerboseMacro( "wrong Image Orientation Patient (0020,0035). Less than 6 values were found." ); } } - - return Unknow; } /** @@ -863,6 +659,24 @@ int File::GetBitsStored() return atoi( strSize.c_str() ); } +/** + * \brief Retrieve the number of Bits Allocated + * (8, 12 -compacted ACR-NEMA files, 16, ...) + * @return The encountered number of Bits Allocated, 0 by default. + * 0 means the file is NOT USABLE. The caller has to check it ! + */ +int File::GetBitsAllocated() +{ + std::string strSize = GetEntryValue(0x0028,0x0100); + if ( strSize == GDCM_UNFOUND ) + { + gdcmVerboseMacro( "(0028,0100) is supposed to be mandatory"); + return 0; // It's supposed to be mandatory + // the caller will have to check + } + return atoi( strSize.c_str() ); +} + /** * \brief Retrieve the high bit position. * \warning The method defaults to 0 when information is Missing. @@ -880,46 +694,6 @@ int File::GetHighBitPosition() return atoi( strSize.c_str() ); } -/** - * \brief Check whether the pixels are signed or UNsigned data. - * \warning The method defaults to false (UNsigned) when information is Missing. - * The responsability of checking this value is left to the caller. - * @return True when signed, false when UNsigned - */ -bool File::IsSignedPixelData() -{ - std::string strSize = GetEntryValue( 0x0028, 0x0103 ); - if ( strSize == GDCM_UNFOUND ) - { - gdcmVerboseMacro( "(0028,0103) is supposed to be mandatory"); - return false; - } - int sign = atoi( strSize.c_str() ); - if ( sign == 0 ) - { - return false; - } - return true; -} - -/** - * \brief Retrieve the number of Bits Allocated - * (8, 12 -compacted ACR-NEMA files, 16, ...) - * @return The encountered number of Bits Allocated, 0 by default. - * 0 means the file is NOT USABLE. The caller has to check it ! - */ -int File::GetBitsAllocated() -{ - std::string strSize = GetEntryValue(0x0028,0x0100); - if ( strSize == GDCM_UNFOUND ) - { - gdcmVerboseMacro( "(0028,0100) is supposed to be mandatory"); - return 0; // It's supposed to be mandatory - // the caller will have to check - } - return atoi( strSize.c_str() ); -} - /** * \brief Retrieve the number of Samples Per Pixel * (1 : gray level, 3 : RGB -1 or 3 Planes-) @@ -938,64 +712,6 @@ int File::GetSamplesPerPixel() return atoi( strSize.c_str() ); } -/** - * \brief Check whether this a monochrome picture or not by accessing - * the "Photometric Interpretation" tag ( 0x0028, 0x0004 ). - * @return true when "MONOCHROME1" or "MONOCHROME2". False otherwise. - */ -bool File::IsMonochrome() -{ - const std::string &PhotometricInterp = GetEntryValue( 0x0028, 0x0004 ); - if ( Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1") - || Util::DicomStringEqual(PhotometricInterp, "MONOCHROME2") ) - { - return true; - } - if ( PhotometricInterp == GDCM_UNFOUND ) - { - gdcmVerboseMacro( "Not found : Photometric Interpretation (0028,0004)"); - } - return false; -} - -/** - * \brief Check whether this a "PALETTE COLOR" picture or not by accessing - * the "Photometric Interpretation" tag ( 0x0028, 0x0004 ). - * @return true when "PALETTE COLOR". False otherwise. - */ -bool File::IsPaletteColor() -{ - std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 ); - if ( PhotometricInterp == "PALETTE COLOR " ) - { - return true; - } - if ( PhotometricInterp == GDCM_UNFOUND ) - { - gdcmVerboseMacro( "Not found : Palette color (0028,0004)"); - } - return false; -} - -/** - * \brief Check whether this a "YBR_FULL" color picture or not by accessing - * the "Photometric Interpretation" tag ( 0x0028, 0x0004 ). - * @return true when "YBR_FULL". False otherwise. - */ -bool File::IsYBRFull() -{ - std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 ); - if ( PhotometricInterp == "YBR_FULL" ) - { - return true; - } - if ( PhotometricInterp == GDCM_UNFOUND ) - { - gdcmVerboseMacro( "Not found : YBR Full (0028,0004)"); - } - return false; -} - /** * \brief Retrieve the Planar Configuration for RGB images * (0 : RGB Pixels , 1 : R Plane + G Plane + B Plane) @@ -1101,53 +817,84 @@ std::string File::GetPixelType() return bitsAlloc + sign; } +/** + * \brief Check whether the pixels are signed or UNsigned data. + * \warning The method defaults to false (UNsigned) when information is Missing. + * The responsability of checking this value is left to the caller. + * @return True when signed, false when UNsigned + */ +bool File::IsSignedPixelData() +{ + std::string strSize = GetEntryValue( 0x0028, 0x0103 ); + if ( strSize == GDCM_UNFOUND ) + { + gdcmVerboseMacro( "(0028,0103) is supposed to be mandatory"); + return false; + } + int sign = atoi( strSize.c_str() ); + if ( sign == 0 ) + { + return false; + } + return true; +} /** - * \brief Recover the offset (from the beginning of the file) - * of *image* pixels (not *icone image* pixels, if any !) - * @return Pixel Offset + * \brief Check whether this a monochrome picture or not by accessing + * the "Photometric Interpretation" tag ( 0x0028, 0x0004 ). + * @return true when "MONOCHROME1" or "MONOCHROME2". False otherwise. */ -size_t File::GetPixelOffset() +bool File::IsMonochrome() { - DocEntry* pxlElement = GetDocEntry(GrPixel,NumPixel); - if ( pxlElement ) + const std::string &PhotometricInterp = GetEntryValue( 0x0028, 0x0004 ); + if ( Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1") + || Util::DicomStringEqual(PhotometricInterp, "MONOCHROME2") ) { - return pxlElement->GetOffset(); + return true; } - else + if ( PhotometricInterp == GDCM_UNFOUND ) { -#ifdef GDCM_DEBUG - std::cout << "Big trouble : Pixel Element (" - << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" - << std::endl; -#endif //GDCM_DEBUG - return 0; + gdcmVerboseMacro( "Not found : Photometric Interpretation (0028,0004)"); } + return false; } /** - * \brief Recover the pixel area length (in Bytes) - * @return Pixel Element Length, as stored in the header - * (NOT the memory space necessary to hold the Pixels - * -in case of embeded compressed image-) - * 0 : NOT USABLE file. The caller has to check. + * \brief Check whether this a "PALETTE COLOR" picture or not by accessing + * the "Photometric Interpretation" tag ( 0x0028, 0x0004 ). + * @return true when "PALETTE COLOR". False otherwise. */ -size_t File::GetPixelAreaLength() +bool File::IsPaletteColor() { - DocEntry* pxlElement = GetDocEntry(GrPixel,NumPixel); - if ( pxlElement ) + std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 ); + if ( PhotometricInterp == "PALETTE COLOR " ) { - return pxlElement->GetLength(); + return true; } - else + if ( PhotometricInterp == GDCM_UNFOUND ) { -#ifdef GDCM_DEBUG - std::cout << "Big trouble : Pixel Element (" - << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" - << std::endl; -#endif //GDCM_DEBUG - return 0; + gdcmVerboseMacro( "Not found : Palette color (0028,0004)"); + } + return false; +} + +/** + * \brief Check whether this a "YBR_FULL" color picture or not by accessing + * the "Photometric Interpretation" tag ( 0x0028, 0x0004 ). + * @return true when "YBR_FULL". False otherwise. + */ +bool File::IsYBRFull() +{ + std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 ); + if ( PhotometricInterp == "YBR_FULL" ) + { + return true; } + if ( PhotometricInterp == GDCM_UNFOUND ) + { + gdcmVerboseMacro( "Not found : YBR Full (0028,0004)"); + } + return false; } /** @@ -1230,36 +977,163 @@ int File::GetLUTNbits() } /** - * \brief gets the info from 0020,0037 : Image Orientation Patient - * (needed to organize DICOM files based on their x,y,z position) - * @param iop adress of the (6)float aray to receive values - * @return cosines of image orientation patient - */ -void File::GetImageOrientationPatient( float iop[6] ) + *\brief gets the info from 0028,1052 : Rescale Intercept + * @return Rescale Intercept + */ +float File::GetRescaleIntercept() { - std::string strImOriPat; - //iop is supposed to be float[6] - iop[0] = iop[1] = iop[2] = iop[3] = iop[4] = iop[5] = 0.; + float resInter = 0.; + /// 0028 1052 DS IMG Rescale Intercept + const std::string &strRescInter = GetEntryValue(0x0028,0x1052); + if ( strRescInter != GDCM_UNFOUND ) + { + if( sscanf( strRescInter.c_str(), "%f", &resInter) != 1 ) + { + // bug in the element 0x0028,0x1052 + gdcmVerboseMacro( "Rescale Intercept (0028,1052) is empty." ); + } + } - // 0020 0037 DS REL Image Orientation (Patient) - if ( (strImOriPat = GetEntryValue(0x0020,0x0037)) != GDCM_UNFOUND ) + return resInter; +} + +/** + *\brief gets the info from 0028,1053 : Rescale Slope + * @return Rescale Slope + */ +float File::GetRescaleSlope() +{ + float resSlope = 1.; + //0028 1053 DS IMG Rescale Slope + std::string strRescSlope = GetEntryValue(0x0028,0x1053); + if ( strRescSlope != GDCM_UNFOUND ) { - if( sscanf( strImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", - &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 ) + if( sscanf( strRescSlope.c_str(), "%f", &resSlope) != 1) { - gdcmVerboseMacro( "Wrong Image Orientation Patient (0020,0037). Less than 6 values were found." ); + // bug in the element 0x0028,0x1053 + gdcmVerboseMacro( "Rescale Slope (0028,1053) is empty."); } } - //For ACR-NEMA - // 0020 0035 DS REL Image Orientation (RET) - else if ( (strImOriPat = GetEntryValue(0x0020,0x0035)) != GDCM_UNFOUND ) + + return resSlope; +} + +/** + * \brief This function is intended to user who doesn't want + * to have to manage a LUT and expects to get an RBG Pixel image + * (or a monochrome one ...) + * \warning to be used with GetImagePixels() + * @return 1 if Gray level, 3 if Color (RGB, YBR or PALETTE COLOR) + */ +int File::GetNumberOfScalarComponents() +{ + if ( GetSamplesPerPixel() == 3 ) { - if( sscanf( strImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", - &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 ) + return 3; + } + + // 0028 0100 US IMG Bits Allocated + // (in order no to be messed up by old RGB images) + if ( GetEntryValue(0x0028,0x0100) == "24" ) + { + return 3; + } + + std::string strPhotometricInterpretation = GetEntryValue(0x0028,0x0004); + + if ( ( strPhotometricInterpretation == "PALETTE COLOR ") ) + { + if ( HasLUT() )// PALETTE COLOR is NOT enough { - gdcmVerboseMacro( "wrong Image Orientation Patient (0020,0035). Less than 6 values were found." ); + return 3; + } + else + { + return 1; } } + + // beware of trailing space at end of string + // DICOM tags are never of odd length + if ( strPhotometricInterpretation == GDCM_UNFOUND || + Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME1") || + Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME2") ) + { + return 1; + } + else + { + // we assume that *all* kinds of YBR are dealt with + return 3; + } +} + +/** + * \brief This function is intended to user that DOESN'T want + * to get RGB pixels image when it's stored as a PALETTE COLOR image + * - the (vtk) user is supposed to know how deal with LUTs - + * \warning to be used with GetImagePixelsRaw() + * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -) + */ +int File::GetNumberOfScalarComponentsRaw() +{ + // 0028 0100 US IMG Bits Allocated + // (in order no to be messed up by old RGB images) + if ( File::GetEntryValue(0x0028,0x0100) == "24" ) + { + return 3; + } + + // we assume that *all* kinds of YBR are dealt with + return GetSamplesPerPixel(); +} + +/** + * \brief Recover the offset (from the beginning of the file) + * of *image* pixels (not *icone image* pixels, if any !) + * @return Pixel Offset + */ +size_t File::GetPixelOffset() +{ + DocEntry* pxlElement = GetDocEntry(GrPixel,NumPixel); + if ( pxlElement ) + { + return pxlElement->GetOffset(); + } + else + { +#ifdef GDCM_DEBUG + std::cout << "Big trouble : Pixel Element (" + << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" + << std::endl; +#endif //GDCM_DEBUG + return 0; + } +} + +/** + * \brief Recover the pixel area length (in Bytes) + * @return Pixel Element Length, as stored in the header + * (NOT the memory space necessary to hold the Pixels + * -in case of embeded compressed image-) + * 0 : NOT USABLE file. The caller has to check. + */ +size_t File::GetPixelAreaLength() +{ + DocEntry* pxlElement = GetDocEntry(GrPixel,NumPixel); + if ( pxlElement ) + { + return pxlElement->GetLength(); + } + else + { +#ifdef GDCM_DEBUG + std::cout << "Big trouble : Pixel Element (" + << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" + << std::endl; +#endif //GDCM_DEBUG + return 0; + } } /** @@ -1343,6 +1217,130 @@ bool File::AnonymizeFile() return true; } +/** + * \brief Performs some consistency checking on various 'File related' + * (as opposed to 'DicomDir related') entries + * then writes in a file all the (Dicom Elements) included the Pixels + * @param fileName file name to write to + * @param filetype Type of the File to be written + * (ACR, ExplicitVR, ImplicitVR) + */ +bool File::Write(std::string fileName, FileType filetype) +{ + std::ofstream *fp = new std::ofstream(fileName.c_str(), + std::ios::out | std::ios::binary); + if (*fp == NULL) + { + gdcmVerboseMacro("Failed to open (write) File: " << fileName.c_str()); + return false; + } + + // Entry : 0002|0000 = group length -> recalculated + ValEntry *e0002 = GetValEntry(0x0002,0x0000); + if( e0002 ) + { + std::ostringstream sLen; + sLen << ComputeGroup0002Length(filetype); + e0002->SetValue(sLen.str()); + } + + // Bits Allocated + if ( GetEntryValue(0x0028,0x0100) == "12") + { + SetValEntry("16", 0x0028,0x0100); + } + + int i_lgPix = GetEntryLength(GrPixel, NumPixel); + if (i_lgPix != -2) + { + // no (GrPixel, NumPixel) element + std::string s_lgPix = Util::Format("%d", i_lgPix+12); + s_lgPix = Util::DicomString( s_lgPix.c_str() ); + InsertValEntry(s_lgPix,GrPixel, 0x0000); + } + + // FIXME : should be nice if we could move it to File + // (or in future gdcmPixelData class) + + // Drop Palette Color, if necessary + if ( GetEntryValue(0x0028,0x0002).c_str()[0] == '3' ) + { + // if SamplesPerPixel = 3, sure we don't need any LUT ! + // Drop 0028|1101, 0028|1102, 0028|1103 + // Drop 0028|1201, 0028|1202, 0028|1203 + + DocEntry *e = GetDocEntry(0x0028,0x01101); + if (e) + { + RemoveEntryNoDestroy(e); + } + e = GetDocEntry(0x0028,0x1102); + if (e) + { + RemoveEntryNoDestroy(e); + } + e = GetDocEntry(0x0028,0x1103); + if (e) + { + RemoveEntryNoDestroy(e); + } + e = GetDocEntry(0x0028,0x01201); + if (e) + { + RemoveEntryNoDestroy(e); + } + e = GetDocEntry(0x0028,0x1202); + if (e) + { + RemoveEntryNoDestroy(e); + } + e = GetDocEntry(0x0028,0x1203); + if (e) + { + RemoveEntryNoDestroy(e); + } + } + +/* +#ifdef GDCM_WORDS_BIGENDIAN + // Super Super hack that will make gdcm a BOMB ! but should + // Fix temporarily the dashboard + BinEntry *b = GetBinEntry(GrPixel,NumPixel); + if ( GetPixelSize() == 16 ) + { + uint16_t *im16 = (uint16_t *)b->GetBinArea(); + int lgr = b->GetLength(); + for( int i = 0; i < lgr / 2; i++ ) + { + im16[i]= (im16[i] >> 8) | (im16[i] << 8 ); + } + } +#endif //GDCM_WORDS_BIGENDIAN +*/ + + Document::WriteContent(fp, filetype); + +/* +#ifdef GDCM_WORDS_BIGENDIAN + // Flip back the pixel ... I told you this is a hack + if ( GetPixelSize() == 16 ) + { + uint16_t *im16 = (uint16_t*)b->GetBinArea(); + int lgr = b->GetLength(); + for( int i = 0; i < lgr / 2; i++ ) + { + im16[i]= (im16[i] >> 8) | (im16[i] << 8 ); + } + } +#endif //GDCM_WORDS_BIGENDIAN +*/ + + fp->close(); + delete fp; + + return true; +} + //----------------------------------------------------------------------------- // Protected /** diff --git a/src/gdcmFile.h b/src/gdcmFile.h index cfd5d662..b8275b03 100644 --- a/src/gdcmFile.h +++ b/src/gdcmFile.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmFile.h,v $ Language: C++ - Date: $Date: 2005/01/28 17:01:30 $ - Version: $Revision: 1.101 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.102 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -74,6 +74,7 @@ enum ModalityType { }; //----------------------------------------------------------------------------- + /** * \brief DICOM elements and their corresponding values (and * additionaly the corresponding DICOM dictionary entry) of the header @@ -91,55 +92,48 @@ enum ModalityType { * protected due to Swig limitations for as Has_a dependency between * File and FileHelper. */ - -//----------------------------------------------------------------------------- class GDCM_EXPORT File : public Document { -protected: - /// \brief In some cases (e.g. for some ACR-NEMA images) the Entry Element - /// Number of the 'Pixel Element' is *not* found at 0x0010. In order to - /// make things easier the parser shall store the proper value in - /// NumPixel to provide a unique access facility. - uint16_t NumPixel; - /// \brief In some cases (e.g. for some ACR-NEMA images) the header entry for - /// the group of pixels is *not* found at 0x7fe0. In order to - /// make things easier the parser shall store the proper value in - /// GrPixel to provide a unique access facility. - uint16_t GrPixel; - public: File(); File( std::string const &filename ); - ~File(); // Standard values and informations contained in the header bool IsReadable(); // Some heuristic based accessors, end user intended + int GetImageNumber(); + ModalityType GetModality(); + + int GetXSize(); + int GetYSize(); + int GetZSize(); + + float GetXSpacing(); + float GetYSpacing(); + float GetZSpacing(); + + float GetXOrigin(); + float GetYOrigin(); + float GetZOrigin(); + + void GetImageOrientationPatient( float iop[6] ); + int GetBitsStored(); int GetBitsAllocated(); + int GetHighBitPosition(); int GetSamplesPerPixel(); int GetPlanarConfiguration(); int GetPixelSize(); - int GetHighBitPosition(); + std::string GetPixelType(); bool IsSignedPixelData(); bool IsMonochrome(); bool IsPaletteColor(); bool IsYBRFull(); - std::string GetPixelType(); - size_t GetPixelOffset(); - size_t GetPixelAreaLength(); - - //Some image informations needed for third package imaging library - int GetXSize(); - int GetYSize(); - int GetZSize(); - - float GetXSpacing(); - float GetYSpacing(); - float GetZSpacing(); + bool HasLUT(); + int GetLUTNbits(); // For rescaling graylevel: float GetRescaleIntercept(); @@ -148,35 +142,24 @@ public: int GetNumberOfScalarComponents(); int GetNumberOfScalarComponentsRaw(); - // To organize DICOM files based on their x,y,z position - void GetImageOrientationPatient( float iop[6] ); - - int GetImageNumber(); - ModalityType GetModality(); - - float GetXOrigin(); - float GetYOrigin(); - float GetZOrigin(); - - bool HasLUT(); - int GetLUTNbits(); - /// Accessor to \ref File::GrPixel uint16_t GetGrPixel() { return GrPixel; } - /// Accessor to \ref File::NumPixel uint16_t GetNumPixel() { return NumPixel; } - /// Replace patient's specific information by 'anonymous' - bool AnonymizeFile(); - - bool Write(std::string fileName, FileType filetype); + size_t GetPixelOffset(); + size_t GetPixelAreaLength(); /// returns the RLE info RLEFramesInfo *GetRLEInfo() { return RLEInfo; } /// Returns the JPEG Fragments info JPEGFragmentsInfo *GetJPEGInfo() { return JPEGInfo; } + /// Replace patient's specific information by 'anonymous' + bool AnonymizeFile(); + + bool Write(std::string fileName, FileType filetype); + protected: /// Initialize DICOM File when none void InitializeDefaultFile(); @@ -186,12 +169,23 @@ protected: /// Store the JPEG fragments info obtained during parsing of pixels. JPEGFragmentsInfo *JPEGInfo; + /// \brief In some cases (e.g. for some ACR-NEMA images) the Entry Element + /// Number of the 'Pixel Element' is *not* found at 0x0010. In order to + /// make things easier the parser shall store the proper value in + /// NumPixel to provide a unique access facility. + uint16_t NumPixel; + /// \brief In some cases (e.g. for some ACR-NEMA images) the header entry for + /// the group of pixels is *not* found at 0x7fe0. In order to + /// make things easier the parser shall store the proper value in + /// GrPixel to provide a unique access facility. + uint16_t GrPixel; + private: void ComputeRLEInfo(); void ComputeJPEGFragmentInfo(); - void ReadAndSkipEncapsulatedBasicOffsetTable(); bool ReadTag(uint16_t, uint16_t); uint32_t ReadTagLength(uint16_t, uint16_t); + void ReadAndSkipEncapsulatedBasicOffsetTable(); }; } // end namespace gdcm diff --git a/src/gdcmFileHelper.cxx b/src/gdcmFileHelper.cxx index fb243911..5e7ed07e 100644 --- a/src/gdcmFileHelper.cxx +++ b/src/gdcmFileHelper.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmFileHelper.cxx,v $ Language: C++ - Date: $Date: 2005/02/02 10:02:18 $ - Version: $Revision: 1.10 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.11 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -124,6 +124,81 @@ FileHelper::~FileHelper() //----------------------------------------------------------------------------- // Public +/** + * \brief Accesses an existing DocEntry (i.e. a Dicom Element) + * through it's (group, element) and modifies it's content with + * the given value. + * @param content new value (string) to substitute with + * @param group group number of the Dicom Element to modify + * @param elem element number of the Dicom Element to modify + */ +bool FileHelper::SetValEntry(std::string const &content, + uint16_t group, uint16_t elem) +{ + return FileInternal->SetValEntry(content,group,elem); +} + + +/** + * \brief Accesses an existing DocEntry (i.e. a Dicom Element) + * through it's (group, element) and modifies it's content with + * the given value. + * @param content new value (void* -> uint8_t*) to substitute with + * @param lgth new value length + * @param group group number of the Dicom Element to modify + * @param elem element number of the Dicom Element to modify + */ +bool FileHelper::SetBinEntry(uint8_t *content, int lgth, + uint16_t group, uint16_t elem) +{ + return FileInternal->SetBinEntry(content,lgth,group,elem); +} + +/** + * \brief Modifies the value of a given DocEntry (Dicom entry) + * when it exists. Create it with the given value when unexistant. + * @param content (string) Value to be set + * @param group Group number of the Entry + * @param elem Element number of the Entry + * \return pointer to the modified/created Dicom entry (NULL when creation + * failed). + */ +ValEntry *FileHelper::InsertValEntry(std::string const &content, + uint16_t group, uint16_t elem) +{ + return FileInternal->InsertValEntry(content,group,elem); +} + +/* + * \brief Modifies the value of a given DocEntry (Dicom entry) + * when it exists. Create it with the given value when unexistant. + * A copy of the binArea is made to be kept in the Document. + * @param binArea (binary) value to be set + * @param group Group number of the Entry + * @param elem Element number of the Entry + * \return pointer to the modified/created Dicom entry (NULL when creation + * failed). + */ +BinEntry *FileHelper::InsertBinEntry(uint8_t *binArea, int lgth, + uint16_t group, uint16_t elem) +{ + return FileInternal->InsertBinEntry(binArea,lgth,group,elem); +} + +/* + * \brief Modifies the value of a given DocEntry (Dicom entry) + * when it exists. Create it with the given value when unexistant. + * A copy of the binArea is made to be kept in the Document. + * @param group Group number of the Entry + * @param elem Element number of the Entry + * \return pointer to the modified/created Dicom entry (NULL when creation + * failed). + */ +SeqEntry *FileHelper::InsertSeqEntry(uint16_t group, uint16_t elem) +{ + return FileInternal->InsertSeqEntry(group,elem); +} + /** * \brief Get the size of the image data * If the image can be RGB (with a lut or by default), the size @@ -346,6 +421,14 @@ size_t FileHelper::GetRawDataSize() return PixelReadConverter->GetRawSize(); } +/** + * \brief Access to the underlying \ref PixelReadConverter RGBA LUT + */ +uint8_t* FileHelper::GetLutRGBA() +{ + return PixelReadConverter->GetLutRGBA(); +} + /** * \brief Writes on disk A SINGLE Dicom file * NO test is performed on processor "Endiannity". @@ -354,7 +437,6 @@ size_t FileHelper::GetRawDataSize() * (any already existing file is over written) * @return false if write fails */ - bool FileHelper::WriteRawData(std::string const &fileName) { std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary ); @@ -511,89 +593,6 @@ bool FileHelper::Write(std::string const &fileName) return check; } -/** - * \brief Accesses an existing DocEntry (i.e. a Dicom Element) - * through it's (group, element) and modifies it's content with - * the given value. - * @param content new value (string) to substitute with - * @param group group number of the Dicom Element to modify - * @param elem element number of the Dicom Element to modify - */ -bool FileHelper::SetValEntry(std::string const &content, - uint16_t group, uint16_t elem) -{ - return FileInternal->SetValEntry(content,group,elem); -} - - -/** - * \brief Accesses an existing DocEntry (i.e. a Dicom Element) - * through it's (group, element) and modifies it's content with - * the given value. - * @param content new value (void* -> uint8_t*) to substitute with - * @param lgth new value length - * @param group group number of the Dicom Element to modify - * @param elem element number of the Dicom Element to modify - */ -bool FileHelper::SetBinEntry(uint8_t *content, int lgth, - uint16_t group, uint16_t elem) -{ - return FileInternal->SetBinEntry(content,lgth,group,elem); -} - -/** - * \brief Modifies the value of a given DocEntry (Dicom entry) - * when it exists. Create it with the given value when unexistant. - * @param content (string) Value to be set - * @param group Group number of the Entry - * @param elem Element number of the Entry - * \return pointer to the modified/created Dicom entry (NULL when creation - * failed). - */ -ValEntry *FileHelper::InsertValEntry(std::string const &content, - uint16_t group, uint16_t elem) -{ - return FileInternal->InsertValEntry(content,group,elem); -} - -/* - * \brief Modifies the value of a given DocEntry (Dicom entry) - * when it exists. Create it with the given value when unexistant. - * A copy of the binArea is made to be kept in the Document. - * @param binArea (binary) value to be set - * @param group Group number of the Entry - * @param elem Element number of the Entry - * \return pointer to the modified/created Dicom entry (NULL when creation - * failed). - */ -BinEntry *FileHelper::InsertBinEntry(uint8_t *binArea, int lgth, - uint16_t group, uint16_t elem) -{ - return FileInternal->InsertBinEntry(binArea,lgth,group,elem); -} - -/* - * \brief Modifies the value of a given DocEntry (Dicom entry) - * when it exists. Create it with the given value when unexistant. - * A copy of the binArea is made to be kept in the Document. - * @param group Group number of the Entry - * @param elem Element number of the Entry - * \return pointer to the modified/created Dicom entry (NULL when creation - * failed). - */ -SeqEntry *FileHelper::InsertSeqEntry(uint16_t group, uint16_t elem) -{ - return FileInternal->InsertSeqEntry(group,elem); -} - -/** - * \brief Access to the underlying \ref PixelReadConverter RGBA LUT - */ -uint8_t* FileHelper::GetLutRGBA() -{ - return PixelReadConverter->GetLutRGBA(); -} - //----------------------------------------------------------------------------- // Protected /** @@ -650,7 +649,7 @@ bool FileHelper::CheckWriteIntegrity() } /** - * \brief + * \brief Update the File to write RAW datas */ void FileHelper::SetWriteToRaw() { @@ -686,7 +685,7 @@ void FileHelper::SetWriteToRaw() } /** - * \brief + * \brief Update the File to write RGB datas */ void FileHelper::SetWriteToRGB() { @@ -759,7 +758,7 @@ void FileHelper::SetWriteToRGB() } /** - * \brief + * \brief Restore the File write mode */ void FileHelper::RestoreWrite() { @@ -783,7 +782,7 @@ void FileHelper::RestoreWrite() } /** - * \brief + * \brief Set in the File the write type to ACR */ void FileHelper::SetWriteFileTypeToACR() { @@ -791,7 +790,7 @@ void FileHelper::SetWriteFileTypeToACR() } /** - * \brief + * \brief Set in the File the write type to Explicit VR */ void FileHelper::SetWriteFileTypeToExplicitVR() { @@ -805,7 +804,7 @@ void FileHelper::SetWriteFileTypeToExplicitVR() } /** - * \brief + * \brief Set in the File the write type to Implicit VR */ void FileHelper::SetWriteFileTypeToImplicitVR() { @@ -820,13 +819,16 @@ void FileHelper::SetWriteFileTypeToImplicitVR() /** - * \brief + * \brief Restore in the File the write type */ void FileHelper::RestoreWriteFileType() { Archive->Restore(0x0002,0x0010); } +/** + * \brief Set the Write not to Libido format + */ void FileHelper::SetWriteToLibido() { ValEntry *oldRow = dynamic_cast @@ -857,7 +859,7 @@ void FileHelper::SetWriteToLibido() } /** - * \brief + * \brief Set the Write not to No Libido format */ void FileHelper::SetWriteToNoLibido() { @@ -875,7 +877,7 @@ void FileHelper::SetWriteToNoLibido() } /** - * \brief + * \brief Restore the Write format */ void FileHelper::RestoreWriteOfLibido() { @@ -884,6 +886,13 @@ void FileHelper::RestoreWriteOfLibido() Archive->Restore(0x0008,0x0010); } +/** + * \brief Copy a ValEntry content + * @param group Group number of the Entry + * @param elem Element number of the Entry + * \return pointer to the modified/created Val Entry (NULL when creation + * failed). + */ ValEntry *FileHelper::CopyValEntry(uint16_t group,uint16_t elem) { DocEntry *oldE = FileInternal->GetDocEntry(group, elem); diff --git a/src/gdcmFileHelper.h b/src/gdcmFileHelper.h index 4848a946..4891f801 100644 --- a/src/gdcmFileHelper.h +++ b/src/gdcmFileHelper.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmFileHelper.h,v $ Language: C++ - Date: $Date: 2005/01/25 15:44:24 $ - Version: $Revision: 1.7 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.8 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -55,6 +55,9 @@ public: void Print(std::ostream &os = std::cout, std::string const & indent = ""); + /// Accessor to \ref File + File *GetFile() { return FileInternal; } + // File methods bool SetValEntry(std::string const &content, uint16_t group, uint16_t elem); @@ -67,9 +70,7 @@ public: uint16_t group, uint16_t elem); SeqEntry *InsertSeqEntry(uint16_t group, uint16_t elem); - /// Accessor to \ref File - File *GetFile() { return FileInternal; } - + // File helpers size_t GetImageDataSize(); size_t GetImageDataRawSize(); @@ -90,15 +91,7 @@ public: uint8_t* GetRawData(); size_t GetRawDataSize(); - // Write pixels of ONE image on hard drive - // No test is made on processor "endianity" - // The user must call his reader correctly - bool WriteRawData (std::string const &fileName); - bool WriteDcmImplVR(std::string const &fileName); - bool WriteDcmExplVR(std::string const &fileName); - bool WriteAcr (std::string const &fileName); - bool Write (std::string const &fileName); - + // LUT uint8_t* GetLutRGBA(); // Write mode @@ -115,6 +108,15 @@ public: void SetWriteType(FileType format) { WriteType = format; }; FileType GetWriteType() { return WriteType; }; + // Write pixels of ONE image on hard drive + // No test is made on processor "endianity" + // The user must call his reader correctly + bool WriteRawData (std::string const &fileName); + bool WriteDcmImplVR(std::string const &fileName); + bool WriteDcmExplVR(std::string const &fileName); + bool WriteAcr (std::string const &fileName); + bool Write (std::string const &fileName); + protected: bool CheckWriteIntegrity(); diff --git a/src/gdcmSQItem.cxx b/src/gdcmSQItem.cxx index 75d99b67..e6b4e1c9 100644 --- a/src/gdcmSQItem.cxx +++ b/src/gdcmSQItem.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSQItem.cxx,v $ Language: C++ - Date: $Date: 2005/02/02 10:00:24 $ - Version: $Revision: 1.65 $ + Date: $Date: 2005/02/02 16:18:48 $ + Version: $Revision: 1.66 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -99,20 +99,6 @@ void SQItem::WriteContent(std::ofstream *fp, FileType filetype) } } -/** - * \brief Remove all entry in the Sequence Item - */ -void SQItem::ClearEntry() -{ - for(ListDocEntry::iterator cc = DocEntries.begin(); - cc != DocEntries.end(); - ++cc) - { - delete *cc; - } - DocEntries.clear(); -} - /** * \brief Inserts *in the right place* any Entry (Dicom Element) * into the Sequence Item @@ -197,6 +183,20 @@ bool SQItem::RemoveEntryNoDestroy(DocEntry *entryToRemove) return false ; } +/** + * \brief Remove all entry in the Sequence Item + */ +void SQItem::ClearEntry() +{ + for(ListDocEntry::iterator cc = DocEntries.begin(); + cc != DocEntries.end(); + ++cc) + { + delete *cc; + } + DocEntries.clear(); +} + /** * \brief Get the first Dicom entry while visiting the SQItem * \return The first DocEntry if found, otherwhise 0 diff --git a/src/gdcmSQItem.h b/src/gdcmSQItem.h index f1d10054..88e1717f 100644 --- a/src/gdcmSQItem.h +++ b/src/gdcmSQItem.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSQItem.h,v $ Language: C++ - Date: $Date: 2005/01/31 12:19:34 $ - Version: $Revision: 1.38 $ + Date: $Date: 2005/02/02 16:18:49 $ + Version: $Revision: 1.39 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -30,6 +30,7 @@ class DocEntry; //----------------------------------------------------------------------------- typedef std::list ListDocEntry; + //----------------------------------------------------------------------------- /** * \brief a SeqEntry is composed by a set of SQItems. @@ -46,10 +47,10 @@ public: virtual void Print(std::ostream &os = std::cout, std::string const & indent = "" ); void WriteContent(std::ofstream *fp, FileType filetype); - void ClearEntry(); bool AddEntry(DocEntry *Entry); // add to the List bool RemoveEntry(DocEntry *EntryToRemove); bool RemoveEntryNoDestroy(DocEntry *EntryToRemove); + void ClearEntry(); DocEntry *GetFirstEntry(); DocEntry *GetNextEntry(); diff --git a/src/gdcmSeqEntry.cxx b/src/gdcmSeqEntry.cxx index 9e510814..ace2fa46 100644 --- a/src/gdcmSeqEntry.cxx +++ b/src/gdcmSeqEntry.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSeqEntry.cxx,v $ Language: C++ - Date: $Date: 2005/02/01 10:29:56 $ - Version: $Revision: 1.52 $ + Date: $Date: 2005/02/02 16:18:49 $ + Version: $Revision: 1.53 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -67,14 +67,7 @@ SeqEntry::SeqEntry( DocEntry *e, int depth ) */ SeqEntry::~SeqEntry() { - for(ListSQItem::iterator cc = Items.begin(); cc != Items.end(); ++cc) - { - delete *cc; - } - if (SeqTerm) - { - delete SeqTerm; - } + ClearSQItem(); } //----------------------------------------------------------------------------- @@ -108,6 +101,38 @@ void SeqEntry::WriteContent(std::ofstream *fp, FileType filetype) binary_write(*fp, seq_term_lg); } +/** + * \brief adds the passed ITEM to the ITEM chained List for this SeQuence. + * @param sqItem SQItem to be pushed back in the SeqEntry + * @param itemNumber ordinal number of the SQItem + * \note NOT end-user intendend method ! + */ +void SeqEntry::AddSQItem(SQItem *sqItem, int itemNumber) +{ +// FIXME : SQItemNumber is supposed to be the ordinal number of the SQItem +// within the Sequence. +// Either only 'push_back' is allowed, +// and we just have to do something like SeqEntry::lastNb++ +// Or we can add (or remove) anywhere, and SQItemNumber will be broken + sqItem->SetSQItemNumber(itemNumber); + Items.push_back(sqItem); +} + +/** + * \brief Remove all SQItem. + */ +void SeqEntry::ClearSQItem() +{ + for(ListSQItem::iterator cc = Items.begin(); cc != Items.end(); ++cc) + { + delete *cc; + } + if (SeqTerm) + { + delete SeqTerm; + } +} + /** * \brief Get the first entry while visiting the SeqEntry * \return The first SQItem if found, otherwhise NULL @@ -170,23 +195,6 @@ unsigned int SeqEntry::GetNumberOfSQItems() return Items.size(); } -/** - * \brief adds the passed ITEM to the ITEM chained List for this SeQuence. - * @param sqItem SQItem to be pushed back in the SeqEntry - * @param itemNumber ordinal number of the SQItem - * \note NOT end-user intendend method ! - */ -void SeqEntry::AddSQItem(SQItem *sqItem, int itemNumber) -{ -// FIXME : SQItemNumber is supposed to be the ordinal number of the SQItem -// within the Sequence. -// Either only 'push_back' is allowed, -// and we just have to do something like SeqEntry::lastNb++ -// Or we can add (or remove) anywhere, and SQItemNumber will be broken - sqItem->SetSQItemNumber(itemNumber); - Items.push_back(sqItem); -} - //----------------------------------------------------------------------------- // Protected diff --git a/src/gdcmSeqEntry.h b/src/gdcmSeqEntry.h index 5e1f996c..f3919280 100644 --- a/src/gdcmSeqEntry.h +++ b/src/gdcmSeqEntry.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmSeqEntry.h,v $ Language: C++ - Date: $Date: 2005/01/31 12:19:34 $ - Version: $Revision: 1.31 $ + Date: $Date: 2005/02/02 16:18:49 $ + Version: $Revision: 1.32 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -28,6 +28,7 @@ namespace gdcm class SQItem; //----------------------------------------------------------------------------- typedef std::list ListSQItem; + //----------------------------------------------------------------------------- /** * \brief a SeqEntry (as opposed to a ValEntry) is a non elementary DocEntry. @@ -46,11 +47,12 @@ public: void Print(std::ostream &os = std::cout, std::string const & indent = "" ); void WriteContent(std::ofstream *fp, FileType filetype); + void AddSQItem(SQItem *it, int itemNumber); + void ClearSQItem(); SQItem *GetFirstSQItem(); SQItem *GetNextSQItem(); SQItem *GetSQItem(int itemNumber); unsigned int GetNumberOfSQItems(); - void AddSQItem(SQItem *it, int itemNumber); /// Sets the delimitor mode void SetDelimitorMode(bool dm) { DelimitorMode = dm; } @@ -61,7 +63,6 @@ public: /// Gets the depth level int GetDepthLevel() const { return SQDepthLevel; } - /// Sets the depth level of a Sequence Entry embedded in a SeQuence void SetDepthLevel(int depth) { SQDepthLevel = depth; } @@ -69,7 +70,6 @@ protected: private: // Variables - /// If this Sequence is in delimitor mode (length =0xffffffff) or not bool DelimitorMode; diff --git a/src/gdcmValEntry.cxx b/src/gdcmValEntry.cxx index 9a7d6538..4fddd883 100644 --- a/src/gdcmValEntry.cxx +++ b/src/gdcmValEntry.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmValEntry.cxx,v $ Language: C++ - Date: $Date: 2005/02/02 10:02:18 $ - Version: $Revision: 1.55 $ + Date: $Date: 2005/02/02 16:18:49 $ + Version: $Revision: 1.56 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -60,50 +60,6 @@ ValEntry::~ValEntry () //----------------------------------------------------------------------------- // Public -/** - * \brief Sets the std::string representable' value of a ValEntry - * @param val value to set - */ -void ValEntry::SetValue(std::string const &val) -{ - // Integers have a special treatement for their length: - int l = val.length(); - if ( l != 0) // To avoid to be cheated by 'zero length' integers - { - const VRKey &vr = GetVR(); - if( vr == "US" || vr == "SS" ) - { - // for multivaluated items - l = (Util::CountSubstring(val, "\\") + 1) * 2; - ContentEntry::SetValue(val); - } - else if( vr == "UL" || vr == "SL" ) - { - // for multivaluated items - l = (Util::CountSubstring(val, "\\") + 1) * 4;; - ContentEntry::SetValue(val); - } - else - { - std::string finalVal = Util::DicomString( val.c_str() ); - gdcmAssertMacro( !(finalVal.size() % 2) ); - - l = finalVal.length(); - ContentEntry::SetValue(finalVal); - } - } - else - { - std::string finalVal = Util::DicomString( val.c_str() ); - gdcmAssertMacro( !(finalVal.size() % 2) ); - - l = finalVal.length(); - ContentEntry::SetValue(finalVal); - } - - SetLength(l); -} - /** * \brief Writes the std::string representable' value of a ValEntry * @param fp already open ofstream pointer @@ -158,6 +114,50 @@ void ValEntry::WriteContent(std::ofstream *fp, FileType filetype) binary_write(*fp, GetValue()); } +/** + * \brief Sets the std::string representable' value of a ValEntry + * @param val value to set + */ +void ValEntry::SetValue(std::string const &val) +{ + // Integers have a special treatement for their length: + int l = val.length(); + if ( l != 0) // To avoid to be cheated by 'zero length' integers + { + const VRKey &vr = GetVR(); + if( vr == "US" || vr == "SS" ) + { + // for multivaluated items + l = (Util::CountSubstring(val, "\\") + 1) * 2; + ContentEntry::SetValue(val); + } + else if( vr == "UL" || vr == "SL" ) + { + // for multivaluated items + l = (Util::CountSubstring(val, "\\") + 1) * 4;; + ContentEntry::SetValue(val); + } + else + { + std::string finalVal = Util::DicomString( val.c_str() ); + gdcmAssertMacro( !(finalVal.size() % 2) ); + + l = finalVal.length(); + ContentEntry::SetValue(finalVal); + } + } + else + { + std::string finalVal = Util::DicomString( val.c_str() ); + gdcmAssertMacro( !(finalVal.size() % 2) ); + + l = finalVal.length(); + ContentEntry::SetValue(finalVal); + } + + SetLength(l); +} + //----------------------------------------------------------------------------- // Protected diff --git a/src/gdcmValEntry.h b/src/gdcmValEntry.h index 05ae4f18..8c13e78f 100644 --- a/src/gdcmValEntry.h +++ b/src/gdcmValEntry.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmValEntry.h,v $ Language: C++ - Date: $Date: 2005/01/25 15:21:20 $ - Version: $Revision: 1.38 $ + Date: $Date: 2005/02/02 16:18:49 $ + Version: $Revision: 1.39 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -27,7 +27,6 @@ namespace gdcm { //----------------------------------------------------------------------------- - /** * \brief Any Dicom Document (File or DicomDir) contains * a set of DocEntry - Dicom entries - @@ -36,8 +35,7 @@ namespace gdcm * whose content is 'std::string representable' : characters, * or integers (loaded in memory as a std::string) * ValEntry is a specialisation of ContentEntry - */ - + */ class GDCM_EXPORT ValEntry : public ContentEntry { public: @@ -50,8 +48,7 @@ public: // Other accessors are inherited from gdcm::ContentEntry - void Print(std::ostream &os = std::cout, - std::string const & indent = ""); + void Print(std::ostream &os = std::cout,std::string const & indent = ""); void WriteContent(std::ofstream *fp, FileType filetype);