X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmHeader.cxx;h=afe3ed329bf5ce308a6f188720a1b6501f4f4afa;hb=5581a576a5749e2335205ece834b92afad111ad8;hp=4d08f021484a20ab231100c7a6c7b95d47721f26;hpb=cb5e6c7cb10e5a644ebb8deb9bb4d35c89f6e736;p=gdcm.git diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index 4d08f021..afe3ed32 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -1,5 +1,8 @@ +// gdcmHeader.cxx + #include "gdcm.h" #include +#include // For nthos: #ifdef _MSC_VER #include @@ -11,22 +14,19 @@ #include #include "gdcmUtil.h" -#define HEADER_LENGHT_TO_READ 256 // on ne lit plus que le debut - -namespace Error { - struct FileReadError { - FileReadError(FILE* fp, const char* Mesg) { - if (feof(fp)) - dbg.Verbose(1, "EOF encountered :", Mesg); - if (ferror(fp)) - dbg.Verbose(1, "Error on reading :", Mesg); - } - }; -} +#define HEADER_LENGTH_TO_READ 256 // on ne lit plus que le debut +#define _MaxSizeLoadElementValue_ 1024 // longueur au dela de laquelle on ne charge plus les valeurs //FIXME: this looks dirty to me... + #define str2num(str, typeNum) *((typeNum *)(str)) +// str est un pointeur dans un tableau de caractères, qui doit contenir, +// à cet endroit la, la représentation binaire d'un entier (16 ou 32 bits) +// je veux récupérer ça ... dans un entier. +// s'il y a une autre solution, évitant des cast et les indirections, +// je suis preneur + VRHT * gdcmHeader::dicom_vr = (VRHT*)0; gdcmDictSet* gdcmHeader::Dicts = new gdcmDictSet(); @@ -38,12 +38,13 @@ void gdcmHeader::Initialise(void) { } gdcmHeader::gdcmHeader (const char* InFilename) { - SetMaxSizeLoadElementValue(1024); + SetMaxSizeLoadElementValue(_MaxSizeLoadElementValue_); filename = InFilename; Initialise(); fp=fopen(InFilename,"rw"); dbg.Error(!fp, "gdcmHeader::gdcmHeader cannot open file", InFilename); ParseHeader(); + AddAndDefaultElements(); } gdcmHeader::~gdcmHeader (void) { @@ -88,8 +89,9 @@ void gdcmHeader::InitVRDict (void) { /** * \ingroup gdcmHeader - * \brief Discover what the swap code is (among little endian, big endian, + * \brief Discover what the swap code is (among little endian, big endian, * bad little endian, bad big endian). + * */ void gdcmHeader::CheckSwap() { @@ -103,7 +105,7 @@ void gdcmHeader::CheckSwap() int lgrLue; char * entCur; - char deb[HEADER_LENGHT_TO_READ]; + char deb[HEADER_LENGTH_TO_READ]; // First, compare HostByteOrder and NetworkByteOrder in order to // determine if we shall need to swap bytes (i.e. the Endian type). @@ -113,8 +115,8 @@ void gdcmHeader::CheckSwap() net2host = false; // The easiest case is the one of a DICOM header, since it possesses a - // file preamble where it suffice to look for the sting "DICM". - lgrLue = fread(deb, 1, HEADER_LENGHT_TO_READ, fp); + // file preamble where it suffice to look for the string "DICM". + lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, fp); entCur = deb + 128; if(memcmp(entCur, "DICM", (size_t)4) == 0) { @@ -200,7 +202,7 @@ void gdcmHeader::CheckSwap() return; default : dbg.Verbose(0, "gdcmHeader::CheckSwap:", - "ACE/NEMA unfound swap info (time to raise bets)"); + "ACR/NEMA unfound swap info (time to raise bets)"); } // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file. @@ -233,6 +235,15 @@ void gdcmHeader::SwitchSwapToBigEndian(void) { sw = 3412; } +void gdcmHeader::GetPixels(size_t lgrTotale, void* _Pixels) { + size_t pixelsOffset; + pixelsOffset = GetPixelOffset(); + fseek(fp, pixelsOffset, SEEK_SET); + fread(_Pixels, 1, lgrTotale, fp); +} + + + /** * \ingroup gdcmHeader * \brief Find the value representation of the current tag. @@ -244,6 +255,11 @@ void gdcmHeader::SwitchSwapToBigEndian(void) { * effectivement lue * @return longueur retenue pour le champ */ + +// --> +// --> Oops +// --> C'etait la description de quoi, ca? +// --> void gdcmHeader::FindVR( ElValue *ElVal) { if (filetype != ExplicitVR) @@ -270,7 +286,7 @@ void gdcmHeader::FindVR( ElValue *ElVal) { // a tag where we expect reading a VR but are in fact we read the // first to bytes of the length. Then we will interogate (through find) // the dicom_vr dictionary with oddities like "\004\0" which crashes - // both GCC and VC++ implentations of the STL map. Hence when the + // both GCC and VC++ implementations of the STL map. Hence when the // expected VR read happens to be non-ascii characters we consider // we hit falsely explicit VR tag. @@ -324,11 +340,66 @@ void gdcmHeader::FindVR( ElValue *ElVal) { /** * \ingroup gdcmHeader * \brief Determines if the Transfer Syntax was allready encountered - * and if it corresponds to a Big Endian one. + * and if it corresponds to a ImplicitVRLittleEndian one. + * + * @return True when ImplicitVRLittleEndian found. False in all other cases. + */ +bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) { + ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2" ) + return true; + return false; +} + +/** + * \ingroup gdcmHeader + * \brief Determines if the Transfer Syntax was allready encountered + * and if it corresponds to a ExplicitVRLittleEndian one. + * + * @return True when ExplicitVRLittleEndian found. False in all other cases. + */ +bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) { + ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.1" ) + return true; + return false; +} + +/** + * \ingroup gdcmHeader + * \brief Determines if the Transfer Syntax was allready encountered + * and if it corresponds to a DeflatedExplicitVRLittleEndian one. + * + * @return True when DeflatedExplicitVRLittleEndian found. False in all other cases. + */ +bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) { + ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.1.99" ) + return true; + return false; +} + + +/** + * \ingroup gdcmHeader + * \brief Determines if the Transfer Syntax was allready encountered + * and if it corresponds to a Explicit VR Big Endian one. * * @return True when big endian found. False in all other cases. */ -bool gdcmHeader::IsBigEndianTransferSyntax(void) { +bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) { ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010); if ( !Element ) return false; @@ -339,11 +410,94 @@ bool gdcmHeader::IsBigEndianTransferSyntax(void) { return false; } -void gdcmHeader::FixFoundLength(ElValue * ElVal, guint32 FoudLength) { + +/** + * \ingroup gdcmHeader + * \brief Determines if the Transfer Syntax was allready encountered + * and if it corresponds to a JPEGBaseLineProcess1 one. + * + * @return True when JPEGBaseLineProcess1found. False in all other cases. + */ +bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) { + ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + string Transfer = 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 allready 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) { + ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.4.51" ) + return true; + return false; +} + + +/** + * \ingroup gdcmHeader + * \brief Determines if the Transfer Syntax was allready 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) { + ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + string Transfer = 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 allready 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) { + ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010); + if ( !Element ) + return false; + LoadElementValueSafe(Element); + string Transfer = Element->GetValue(); + if ( Transfer == "1.2.840.10008.1.2.4.53" ) + return true; + return false; +} + +// +// Euhhhhhhh +// Il y en a encore DIX-SEPT, comme ça. +// Il faudrait trouver qq chose + rusé ... +// +// --> probablement TOUS les supprimer (Eric dixit) +// + + +void gdcmHeader::FixFoundLength(ElValue * ElVal, guint32 FoundLength) { // Heuristic: a final fix. - if ( FoudLength == 0xffffffff) - FoudLength = 0; - ElVal->SetLength(FoudLength); + if ( FoundLength == 0xffffffff) + FoundLength = 0; + ElVal->SetLength(FoundLength); } guint32 gdcmHeader::FindLengthOB(void) { @@ -358,18 +512,22 @@ guint32 gdcmHeader::FindLengthOB(void) { while ( ! FoundSequenceDelimiter) { g = ReadInt16(); n = ReadInt16(); + if (errno == 1) + return 0; TotalLength += 4; // We even have to decount the group and element if ( g != 0xfffe ) { dbg.Verbose(1, "gdcmHeader::FindLengthOB: ", "wrong group for an item sequence."); - throw Error::FileReadError(fp, "gdcmHeader::FindLengthOB"); + errno = 1; + return 0; } if ( n == 0xe0dd ) FoundSequenceDelimiter = true; else if ( n != 0xe000) { dbg.Verbose(1, "gdcmHeader::FindLengthOB: ", "wrong element for an item sequence."); - throw Error::FileReadError(fp, "gdcmHeader::FindLengthOB"); + errno = 1; + return 0; } ItemLength = ReadInt32(); TotalLength += ItemLength + 4; // We add 4 bytes since we just read @@ -417,7 +575,7 @@ void gdcmHeader::FindLength(ElValue * ElVal) { // in little endian, and big endian coding only starts at the next // group. The corresponding code can be hard to analyse and adds // many additional unnecessary tests for regular tags. - // * the second strategy consist in waiting for trouble, that shall appear + // * the second strategy consists in waiting for trouble, that shall appear // when we find the first group with big endian encoding. This is // easy to detect since the length of a "Group Length" tag (the // ones with zero as element number) has to be of 4 (0x0004). When we @@ -431,16 +589,19 @@ void gdcmHeader::FindLength(ElValue * ElVal) { // endian encoding". When this is the case, chances are we got our // hands on a big endian encoded file: we switch the swap code to // big endian and proceed... - if ( (element == 0) && (length16 == 1024) ) { - if ( ! IsBigEndianTransferSyntax() ) - throw Error::FileReadError(fp, "gdcmHeader::FindLength"); + if ( (element == 0x000) && (length16 == 0x0400) ) { + if ( ! IsExplicitVRBigEndianTransferSyntax() ) { + dbg.Verbose(0, "gdcmHeader::FindLength", "not explicit VR"); + errno = 1; + return; + } length16 = 4; SwitchSwapToBigEndian(); // Restore the unproperly loaded values i.e. the group, the element // and the dictionary entry depending on them. guint16 CorrectGroup = SwapShort(ElVal->GetGroup()); guint16 CorrectElem = SwapShort(ElVal->GetElement()); - gdcmDictEntry * NewTag = IsInDicts(CorrectGroup, CorrectElem); + gdcmDictEntry * NewTag = GetDictEntryByKey(CorrectGroup, CorrectElem); if (!NewTag) { // This correct tag is not in the dictionary. Create a new one. NewTag = new gdcmDictEntry(CorrectGroup, CorrectElem); @@ -550,6 +711,12 @@ void gdcmHeader::LoadElementValue(ElValue * ElVal) { fseek(fp, (long)ElVal->GetOffset(), SEEK_SET); // Sequences not treated yet ! + // + // Ne faudrait-il pas au contraire trouver immediatement + // une maniere 'propre' de traiter les sequences (vr = SQ) + // car commencer par les ignorer risque de conduire a qq chose + // qui pourrait ne pas etre generalisable + // if( vr == "SQ" ) SkipLoad = true; @@ -562,7 +729,9 @@ void gdcmHeader::LoadElementValue(ElValue * ElVal) { // The group length doesn't represent data to be loaded in memory, since // each element of the group shall be loaded individualy. if( elem == 0 ) - SkipLoad = true; + //SkipLoad = true; // modif sauvage JPR + // On charge la longueur du groupe + // quand l'element 0x0000 est présent ! if ( SkipLoad ) { // FIXME the following skip is not necessary @@ -579,6 +748,10 @@ void gdcmHeader::LoadElementValue(ElValue * ElVal) { } // Values bigger than specified are not loaded. + // + // En fait, c'est les elements dont la longueur est superieure + // a celle fixee qui ne sont pas charges + // if (length > MaxSizeLoadElementValue) { ostringstream s; s << "gdcm::NotLoaded."; @@ -618,7 +791,7 @@ void gdcmHeader::LoadElementValue(ElValue * ElVal) { item_read = fread(NewValue, (size_t)length, (size_t)1, fp); if ( item_read != 1 ) { free(NewValue); - Error::FileReadError(fp, "gdcmHeader::LoadElementValue"); + dbg.Verbose(1, "gdcmHeader::LoadElementValue","unread element value"); ElVal->SetValue("gdcm::UnRead"); return; } @@ -644,8 +817,12 @@ guint16 gdcmHeader::ReadInt16(void) { guint16 g; size_t item_read; item_read = fread (&g, (size_t)2,(size_t)1, fp); - if ( item_read != 1 ) - throw Error::FileReadError(fp, "gdcmHeader::ReadInt16"); + errno = 0; + if ( item_read != 1 ) { + dbg.Verbose(1, "gdcmHeader::ReadInt16", " File read error"); + errno = 1; + return 0; + } g = SwapShort(g); return g; } @@ -654,12 +831,62 @@ guint32 gdcmHeader::ReadInt32(void) { guint32 g; size_t item_read; item_read = fread (&g, (size_t)4,(size_t)1, fp); - if ( item_read != 1 ) - throw Error::FileReadError(fp, "gdcmHeader::ReadInt32"); + errno = 0; + if ( item_read != 1 ) { + dbg.Verbose(1, "gdcmHeader::ReadInt32", " File read error"); + errno = 1; + return 0; + } g = SwapLong(g); return g; } +/** + * \ingroup gdcmHeader + * \brief Build a new Element Value from all the low level arguments. + * Check for existence of dictionary entry, and build + * a default one when absent. + * @param Group group of the underlying DictEntry + * @param Elem element of the underlying DictEntry + */ +ElValue* gdcmHeader::NewElValueByKey(guint16 Group, guint16 Elem) { + // Find out if the tag we encountered is in the dictionaries: + gdcmDictEntry * NewTag = GetDictEntryByKey(Group, Elem); + if (!NewTag) + NewTag = new gdcmDictEntry(Group, Elem); + + ElValue* NewElVal = new ElValue(NewTag); + if (!NewElVal) { + dbg.Verbose(1, "gdcmHeader::NewElValueByKey", + "failed to allocate ElValue"); + return (ElValue*)0; + } + return NewElVal; +} + +/** + * \ingroup gdcmHeader + * \brief Build a new Element Value from all the low level arguments. + * Check for existence of dictionary entry, and build + * a default one when absent. + * @param Name Name of the underlying DictEntry + */ +ElValue* gdcmHeader::NewElValueByName(string Name) { + + gdcmDictEntry * NewTag = GetDictEntryByName(Name); + if (!NewTag) + NewTag = new gdcmDictEntry(0xffff, 0xffff, "LO", "Unknown", Name); + + ElValue* NewElVal = new ElValue(NewTag); + if (!NewElVal) { + dbg.Verbose(1, "gdcmHeader::ObtainElValueByName", + "failed to allocate ElValue"); + return (ElValue*)0; + } + return NewElVal; +} + + /** * \ingroup gdcmHeader * \brief Read the next tag without loading it's value @@ -671,32 +898,19 @@ ElValue * gdcmHeader::ReadNextElement(void) { guint16 n; ElValue * NewElVal; - try { - g = ReadInt16(); - n = ReadInt16(); - } - catch ( Error::FileReadError ) { + g = ReadInt16(); + n = ReadInt16(); + if (errno == 1) // We reached the EOF (or an error occured) and header parsing // has to be considered as finished. return (ElValue *)0; - } - - // Find out if the tag we encountered is in the dictionaries: - gdcmDictEntry * NewTag = IsInDicts(g, n); - if (!NewTag) - NewTag = new gdcmDictEntry(g, n); - - NewElVal = new ElValue(NewTag); - if (!NewElVal) { - dbg.Verbose(1, "ReadNextElement: failed to allocate ElValue"); - return (ElValue*)0; - } - + + NewElVal = NewElValueByKey(g, n); FindVR(NewElVal); - try { FindLength(NewElVal); } - catch ( Error::FileReadError ) { // Call it quits + FindLength(NewElVal); + if (errno == 1) + // Call it quits return (ElValue *)0; - } NewElVal->SetOffset(ftell(fp)); return NewElVal; } @@ -731,8 +945,9 @@ bool gdcmHeader::IsAnInteger(ElValue * ElVal) { return true; if ( (group == 0x0028) && (element == 0x0005) ) - // This tag is retained from ACR/NEMA - // CHECKME Why should "Image Dimensions" be a single integer ? + // The "Image Dimensions" tag is retained from ACR/NEMA and contains + // the number of dimensions of the contained object (1 for Signal, + // 2 for Image, 3 for Volume, 4 for Sequence). return true; if ( (group == 0x0028) && (element == 0x0200) ) @@ -757,7 +972,7 @@ size_t gdcmHeader::GetPixelOffset(void) { guint16 grPixel; guint16 numPixel; string ImageLocation = GetPubElValByName("Image Location"); - if ( ImageLocation == "UNFOUND" ) { + if ( ImageLocation == "gdcm::Unfound" ) { grPixel = 0x7fe0; } else { grPixel = (guint16) atoi( ImageLocation.c_str() ); @@ -775,25 +990,82 @@ size_t gdcmHeader::GetPixelOffset(void) { return 0; } -gdcmDictEntry * gdcmHeader::IsInDicts(guint32 group, guint32 element) { +/** + * \ingroup gdcmHeader + * \brief Searches both the public and the shadow dictionary (when they + * exist) for the presence of the DictEntry with given + * group and element. The public dictionary has precedence on the + * shadow one. + * @param group group of the searched DictEntry + * @earam element element of the searched DictEntry + * @return Corresponding DictEntry when it exists, NULL otherwise. + */ +gdcmDictEntry * gdcmHeader::GetDictEntryByKey(guint16 group, guint16 element) { gdcmDictEntry * found = (gdcmDictEntry*)0; if (!RefPubDict && !RefShaDict) { - //FIXME build a default dictionary ! - printf("FIXME in gdcmHeader::IsInDicts\n"); + dbg.Verbose(0, "FIXME in gdcmHeader::GetDictEntry", + "we SHOULD have a default dictionary"); } if (RefPubDict) { - found = RefPubDict->GetTag(group, element); + found = RefPubDict->GetTagByKey(group, element); if (found) return found; } if (RefShaDict) { - found = RefShaDict->GetTag(group, element); + found = RefShaDict->GetTagByKey(group, element); if (found) return found; } return found; } +/** + * \ingroup gdcmHeader + * \brief Searches both the public and the shadow dictionary (when they + * exist) for the presence of the DictEntry with given name. + * The public dictionary has precedence on the shadow one. + * @earam Name name of the searched DictEntry + * @return Corresponding DictEntry when it exists, NULL otherwise. + */ +gdcmDictEntry * gdcmHeader::GetDictEntryByName(string Name) { + gdcmDictEntry * found = (gdcmDictEntry*)0; + if (!RefPubDict && !RefShaDict) { + dbg.Verbose(0, "FIXME in gdcmHeader::GetDictEntry", + "we SHOULD have a default dictionary"); + } + if (RefPubDict) { + found = RefPubDict->GetTagByName(Name); + if (found) + return found; + } + if (RefShaDict) { + found = RefShaDict->GetTagByName(Name); + if (found) + return found; + } + return found; +} + +list * gdcmHeader::GetPubTagNames(void) { + list * Result = new list; + TagKeyHT entries = RefPubDict->GetEntries(); + + for (TagKeyHT::iterator tag = entries.begin(); tag != entries.end(); ++tag){ + Result->push_back( tag->second->GetName() ); + } + return Result; +} + +map > * gdcmHeader::GetPubTagNamesByCategory(void) { + map > * Result = new map >; + TagKeyHT entries = RefPubDict->GetEntries(); + + for (TagKeyHT::iterator tag = entries.begin(); tag != entries.end(); ++tag){ + (*Result)[tag->second->GetFourth()].push_back(tag->second->GetName()); + } + return Result; +} + string gdcmHeader::GetPubElValByNumber(guint16 group, guint16 element) { return PubElVals.GetElValueByNumber(group, element); } @@ -838,7 +1110,6 @@ string gdcmHeader::GetShaElValRepByName(string TagName) { return elem->GetVR(); } - string gdcmHeader::GetElValByNumber(guint16 group, guint16 element) { string pub = GetPubElValByNumber(group, element); if (pub.length()) @@ -869,7 +1140,63 @@ string gdcmHeader::GetElValRepByName(string TagName) { /** * \ingroup gdcmHeader - * \brief Parses the header of the file but does NOT load element values. + * \brief Accesses an existing ElValue in the PubElVals of this instance + * through it's (group, element) and modifies it's content with + * the given value. + * @param content new value to substitute with + * @param group group of the ElVal to modify + * @param element element of the ElVal to modify + */ +int gdcmHeader::SetPubElValByNumber(string content, guint16 group, + guint16 element) +{ + //CLEANME TagKey key = gdcmDictEntry::TranslateToKey(group, element); + //CLEANME PubElVals.tagHt[key]->SetValue(content); + return ( PubElVals.SetElValueByNumber (content, group, element) ); +} + +/** + * \ingroup gdcmHeader + * \brief Accesses an existing ElValue in the PubElVals of this instance + * through tag name and modifies it's content with the given value. + * @param content new value to substitute with + * @param TagName name of the tag to be modified + */ +int gdcmHeader::SetPubElValByName(string content, string TagName) { + //CLEANME TagKey key = gdcmDictEntry::TranslateToKey(group, element); + //CLEANME PubElVals.tagHt[key]->SetValue(content); + return ( PubElVals.SetElValueByName (content, TagName) ); +} + +/** + * \ingroup gdcmHeader + * \brief Accesses an existing ElValue in the ShaElVals of this instance + * through it's (group, element) and modifies it's content with + * the given value. + * @param content new value to substitute with + * @param group group of the ElVal to modify + * @param element element of the ElVal to modify + */ +int gdcmHeader::SetShaElValByNumber(string content, + guint16 group, guint16 element) +{ + return ( ShaElVals.SetElValueByNumber (content, group, element) ); +} + +/** + * \ingroup gdcmHeader + * \brief Accesses an existing ElValue in the ShaElVals of this instance + * through tag name and modifies it's content with the given value. + * @param content new value to substitute with + * @param TagName name of the tag to be modified + */ +int gdcmHeader::SetShaElValByName(string content, string TagName) { + return ( ShaElVals.SetElValueByName (content, TagName) ); +} + +/** + * \ingroup gdcmHeader + * \brief Parses the header of the file but WITHOUT loading element values. */ void gdcmHeader::ParseHeader(void) { ElValue * newElValue = (ElValue *)0; @@ -882,16 +1209,45 @@ void gdcmHeader::ParseHeader(void) { } } +/** + * \ingroup gdcmHeader + * \brief Once the header is parsed add some gdcm convenience/helper elements + * in the ElValSet. For example add: + * - gdcmImageType which is an entry containing a short for the + * type of image and whose value ranges in + * I8 (unsigned 8 bit image) + * I16 (unsigned 8 bit image) + * IS16 (signed 8 bit image) + * - gdcmXsize, gdcmYsize, gdcmZsize whose values are respectively + * the ones of the official DICOM fields Rows, Columns and Planes. + */ +void gdcmHeader::AddAndDefaultElements(void) { + ElValue* NewEntry = (ElValue*)0; + + NewEntry = NewElValueByName("gdcmXSize"); + NewEntry->SetValue(GetElValByName("Rows")); + PubElVals.Add(NewEntry); + + NewEntry = NewElValueByName("gdcmYSize"); + NewEntry->SetValue(GetElValByName("Columns")); + PubElVals.Add(NewEntry); + + NewEntry = NewElValueByName("gdcmZSize"); + NewEntry->SetValue(GetElValByName("Planes")); + PubElVals.Add(NewEntry); +} + /** * \ingroup gdcmHeader * \brief Loads the element values of all the elements present in the * public tag based hash table. */ void gdcmHeader::LoadElements(void) { - rewind(fp); + rewind(fp); TagElValueHT ht = PubElVals.GetTagHt(); - for (TagElValueHT::iterator tag = ht.begin(); tag != ht.end(); ++tag) + for (TagElValueHT::iterator tag = ht.begin(); tag != ht.end(); ++tag) { LoadElementValue(tag->second); + } } void gdcmHeader::PrintPubElVal(ostream & os) {