X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmHeader.cxx;h=49933b6895ca9f63351abbf8b714166e448b86b2;hb=128a3882af9bfd5d3ad4d2512ba3646182c15ffb;hp=a8966f1512a7e57e6a2cf2dda41b2e15ae199947;hpb=71f64e7a420374811ea79d211d5558dd103bcfe8;p=gdcm.git diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index a8966f15..49933b68 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -39,6 +39,9 @@ const unsigned int gdcmHeader::MAX_SIZE_LOAD_ELEMENT_VALUE = 4096; * @param enable_sequences = true to allow the header * to be parsed *inside* the SeQuences, * when they have an actual length + *\TODO : may be we need one more bool, + * to allow skipping the private elements while parsing the header + * in order to save space */ gdcmHeader::gdcmHeader(const char *InFilename, bool exception_on_error, @@ -54,7 +57,7 @@ gdcmHeader::gdcmHeader(const char *InFilename, if ( !OpenFile(exception_on_error)) return; ParseHeader(); - LoadElements(); + LoadHeaderEntries(); CloseFile(); } @@ -85,16 +88,17 @@ gdcmHeader::~gdcmHeader (void) { /** * \ingroup gdcmHeader - * \brief + * \brief Prints the Header Entries (Dicom Elements) + * both from the H Table and the chained list * @return */ -void gdcmHeader::PrintPubElVal(std::ostream & os) { - PubElValSet.Print(os); +void gdcmHeader::PrintPubEntry(std::ostream & os) { + PubEntrySet.Print(os); } /** * \ingroup gdcmHeader - * \brief + * \brief Prints The Dict Entries of THE public Dicom Dictionnry * @return */ void gdcmHeader::PrintPubDict(std::ostream & os) { @@ -103,29 +107,28 @@ void gdcmHeader::PrintPubDict(std::ostream & os) { //----------------------------------------------------------------------------- // Public - /** * \ingroup gdcmHeader * \brief This predicate, based on hopefully reasonable heuristics, * decides whether or not the current gdcmHeader was properly parsed * and contains the mandatory information for being considered as - * a well formed and usable image. - * @return true when gdcmHeader is the one of a reasonable Dicom file, + * a well formed and usable Dicom/Acr File. + * @return true when gdcmHeader is the one of a reasonable Dicom/Acr file, * false otherwise. */ bool gdcmHeader::IsReadable(void) { - std::string res = GetPubElValByNumber(0x0028, 0x0005); - if ( res != GDCM_UNFOUND - && atoi(res.c_str()) > 4 ) { + std::string res = GetEntryByNumber(0x0028, 0x0005); + if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 ) { return false; // Image Dimensions } - if ( GetPubElValByNumber(0x0028, 0x0100) == GDCM_UNFOUND ) + + if ( !GetHeaderEntryByNumber(0x0028, 0x0100) ) return false; // "Bits Allocated" - if ( GetPubElValByNumber(0x0028, 0x0101) == GDCM_UNFOUND ) + if ( !GetHeaderEntryByNumber(0x0028, 0x0101) ) return false; // "Bits Stored" - if ( GetPubElValByNumber(0x0028, 0x0102) == GDCM_UNFOUND ) + if ( !GetHeaderEntryByNumber(0x0028, 0x0102) ) return false; // "High Bit" - if ( GetPubElValByNumber(0x0028, 0x0103) == GDCM_UNFOUND ) + if ( !GetHeaderEntryByNumber(0x0028, 0x0103) ) return false; // "Pixel Representation" return true; } @@ -138,10 +141,11 @@ bool gdcmHeader::IsReadable(void) { * @return True when ImplicitVRLittleEndian found. False in all other cases. */ bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry *Element = GetHeaderEntryByNumber(0x0002, 0x0010); if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + std::string Transfer = Element->GetValue(); if ( Transfer == "1.2.840.10008.1.2" ) return true; @@ -156,10 +160,11 @@ bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) { * @return True when ExplicitVRLittleEndian found. False in all other cases. */ bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + std::string Transfer = Element->GetValue(); if ( Transfer == "1.2.840.10008.1.2.1" ) return true; @@ -174,10 +179,11 @@ bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) { * @return True when DeflatedExplicitVRLittleEndian found. False in all other cases. */ bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + std::string Transfer = Element->GetValue(); if ( Transfer == "1.2.840.10008.1.2.1.99" ) return true; @@ -192,10 +198,11 @@ bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) { * @return True when big endian found. False in all other cases. */ bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + std::string Transfer = Element->GetValue(); if ( Transfer == "1.2.840.10008.1.2.2" ) //1.2.2 ??? A verifier ! return true; @@ -210,10 +217,11 @@ bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) { * @return True when JPEGBaseLineProcess1found. False in all other cases. */ bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + std::string Transfer = Element->GetValue(); if ( Transfer == "1.2.840.10008.1.2.4.50" ) return true; @@ -228,10 +236,11 @@ bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) { * @return True when JPEGExtendedProcess2-4 found. False in all other cases. */ bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + std::string Transfer = Element->GetValue(); if ( Transfer == "1.2.840.10008.1.2.4.51" ) return true; @@ -246,10 +255,11 @@ bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) { * @return True when JPEGExtendedProcess3-5 found. False in all other cases. */ bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + std::string Transfer = Element->GetValue(); if ( Transfer == "1.2.840.10008.1.2.4.52" ) return true; @@ -265,10 +275,11 @@ bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) { * other cases. */ bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + std::string Transfer = Element->GetValue(); if ( Transfer == "1.2.840.10008.1.2.4.53" ) return true; @@ -284,10 +295,11 @@ bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) { * other cases. */ bool gdcmHeader::IsRLELossLessTransferSyntax(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + std::string Transfer = Element->GetValue(); if ( Transfer == "1.2.840.10008.1.2.5" ) return true; @@ -296,16 +308,19 @@ bool gdcmHeader::IsRLELossLessTransferSyntax(void) { /** * \ingroup gdcmHeader - * \brief + * \brief Determines if Transfer Syntax was already encountered + * and if it corresponds to a JPEG Lossless one. * - * @return + * @return True when RLE Lossless found. False in all + * other cases. */ bool gdcmHeader::IsJPEGLossless(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); // faire qq chose d'intelligent a la place de ça if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + const char * Transfert = Element->GetValue().c_str(); if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true; if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true; @@ -323,10 +338,11 @@ bool gdcmHeader::IsJPEGLossless(void) { * other cases. */ bool gdcmHeader::IsJPEG2000(void) { - gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010); + gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010); if ( !Element ) return false; - LoadElementValueSafe(Element); + LoadHeaderEntrySafe(Element); + std::string Transfer = Element->GetValue(); if ( (Transfer == "1.2.840.10008.1.2.4.90") || (Transfer == "1.2.840.10008.1.2.4.91") ) @@ -340,19 +356,17 @@ bool gdcmHeader::IsJPEG2000(void) { * @return True when the file is a dicom version 3. */ bool gdcmHeader::IsDicomV3(void) { - if ( (filetype == ExplicitVR) - || (filetype == ImplicitVR) ) - return true; - return false; + // Checking if Transfert Syntax exists is enough + return (GetHeaderEntryByNumber(0x0002, 0x0010) != NULL); } /** * \ingroup gdcmHeader - * \brief + * \brief returns the File Type + * (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown) * @return */ -FileType gdcmHeader::GetFileType(void) -{ +FileType gdcmHeader::GetFileType(void) { return(filetype); } @@ -360,11 +374,12 @@ FileType gdcmHeader::GetFileType(void) * \ingroup gdcmHeader * \brief Retrieve the number of columns of image. * @return The encountered size when found, 0 by default. + * 0 means the file is NOT USABLE. The caller will have to check */ int gdcmHeader::GetXSize(void) { // We cannot check for "Columns" because the "Columns" tag is present // both in IMG (0028,0011) and OLY (6000,0011) sections of the dictionary. - std::string StrSize = GetPubElValByNumber(0x0028,0x0011); + std::string StrSize = GetEntryByNumber(0x0028,0x0011); if (StrSize == GDCM_UNFOUND) return 0; return atoi(StrSize.c_str()); @@ -374,18 +389,19 @@ int gdcmHeader::GetXSize(void) { * \ingroup gdcmHeader * \brief Retrieve the number of lines of image. * \warning The defaulted value is 1 as opposed to gdcmHeader::GetXSize() - * @return The encountered size when found, 1 by default. + * @return The encountered size when found, 1 by default + * (The file contains a Signal, not an Image). */ int gdcmHeader::GetYSize(void) { // We cannot check for "Rows" because the "Rows" tag is present // both in IMG (0028,0010) and OLY (6000,0010) sections of the dictionary. - std::string StrSize = GetPubElValByNumber(0x0028,0x0010); + std::string StrSize = GetEntryByNumber(0x0028,0x0010); if (StrSize != GDCM_UNFOUND) return atoi(StrSize.c_str()); if ( IsDicomV3() ) return 0; else - // The Rows (0028,0010) entry is optional for ACR/NEMA. It might + // The Rows (0028,0010) entry was optional for ACR/NEMA. It might // hence be a signal (1d image). So we default to 1: return 1; } @@ -397,19 +413,19 @@ int gdcmHeader::GetYSize(void) { * \warning When present we consider the "Number of Frames" as the third * dimension. When absent we consider the third dimension as * being the "Planes" tag content. - * @return The encountered size when found, 1 by default. + * @return The encountered size when found, 1 by default (single image). */ int gdcmHeader::GetZSize(void) { // Both DicomV3 and ACR/Nema consider the "Number of Frames" // as the third dimension. - std::string StrSize = GetPubElValByNumber(0x0028,0x0008); + std::string StrSize = GetEntryByNumber(0x0028,0x0008); if (StrSize != GDCM_UNFOUND) return atoi(StrSize.c_str()); // We then consider the "Planes" entry as the third dimension [we // cannot retrieve by name since "Planes tag is present both in // IMG (0028,0012) and OLY (6000,0012) sections of the dictionary]. - StrSize = GetPubElValByNumber(0x0028,0x0012); + StrSize = GetEntryByNumber(0x0028,0x0012); if (StrSize != GDCM_UNFOUND) return atoi(StrSize.c_str()); return 1; @@ -417,15 +433,17 @@ int gdcmHeader::GetZSize(void) { /** * \ingroup gdcmHeader - * \brief Retrieve the number of Bits Stored + * \brief Retrieve the number of Bits Stored (actually used) * (as opposite to number of Bits Allocated) * * @return The encountered number of Bits Stored, 0 by default. + * 0 means the file is NOT USABLE. The caller has to check it ! */ int gdcmHeader::GetBitsStored(void) { - std::string StrSize = GetPubElValByNumber(0x0028,0x0101); + std::string StrSize = GetEntryByNumber(0x0028,0x0101); if (StrSize == GDCM_UNFOUND) - return 1; + return 0; // It's supposed to be mandatory + // the caller will have to check return atoi(StrSize.c_str()); } @@ -435,11 +453,13 @@ int gdcmHeader::GetBitsStored(void) { * (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 gdcmHeader::GetBitsAllocated(void) { - std::string StrSize = GetPubElValByNumber(0x0028,0x0100); + std::string StrSize = GetEntryByNumber(0x0028,0x0100); if (StrSize == GDCM_UNFOUND) - return 1; + return 0; // It's supposed to be mandatory + // the caller will have to check return atoi(StrSize.c_str()); } @@ -449,11 +469,13 @@ int gdcmHeader::GetBitsAllocated(void) { * (1 : gray level, 3 : RGB -1 or 3 Planes-) * * @return The encountered number of Samples Per Pixel, 1 by default. + * (Gray level Pixels) */ int gdcmHeader::GetSamplesPerPixel(void) { - std::string StrSize = GetPubElValByNumber(0x0028,0x0002); + std::string StrSize = GetEntryByNumber(0x0028,0x0002); if (StrSize == GDCM_UNFOUND) return 1; // Well, it's supposed to be mandatory ... + // but sometimes it's missing : we assume Gray pixels return atoi(StrSize.c_str()); } @@ -465,7 +487,7 @@ int gdcmHeader::GetSamplesPerPixel(void) { * @return The encountered Planar Configuration, 0 by default. */ int gdcmHeader::GetPlanarConfiguration(void) { - std::string StrSize = GetPubElValByNumber(0x0028,0x0006); + std::string StrSize = GetEntryByNumber(0x0028,0x0006); if (StrSize == GDCM_UNFOUND) return 0; return atoi(StrSize.c_str()); @@ -474,8 +496,8 @@ int gdcmHeader::GetPlanarConfiguration(void) { /** * \ingroup gdcmHeader * \brief Return the size (in bytes) of a single pixel of data. - * @return The size in bytes of a single pixel of data. - * + * @return The size in bytes of a single pixel of data; 0 by default + * 0 means the file is NOT USABLE; the caller will have to check */ int gdcmHeader::GetPixelSize(void) { std::string PixelType = GetPixelType(); @@ -501,11 +523,10 @@ int gdcmHeader::GetPixelSize(void) { * - 32S signed 32 bit, * \warning 12 bit images appear as 16 bit. * \ 24 bit images appear as 8 bit - * @return + * @return 0S if nothing found. NOT USABLE file. The caller has to check */ std::string gdcmHeader::GetPixelType(void) { - std::string BitsAlloc; - BitsAlloc = GetPubElValByNumber(0x0028, 0x0100); // Bits Allocated + std::string BitsAlloc = GetEntryByNumber(0x0028, 0x0100); // Bits Allocated if (BitsAlloc == GDCM_UNFOUND) { dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated"); BitsAlloc = std::string("16"); @@ -515,8 +536,7 @@ std::string gdcmHeader::GetPixelType(void) { else if (BitsAlloc == "24") // (in order no to be messed up BitsAlloc = std::string("8"); // by old RGB images) - std::string Signed; - Signed = GetPubElValByNumber(0x0028, 0x0103); // "Pixel Representation" + std::string Signed = GetEntryByNumber(0x0028, 0x0103); // "Pixel Representation" if (Signed == GDCM_UNFOUND) { dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation"); BitsAlloc = std::string("0"); @@ -535,7 +555,7 @@ std::string gdcmHeader::GetPixelType(void) { */ size_t gdcmHeader::GetPixelOffset(void) { // If this file complies with the norm we should encounter the - // "Image Location" tag (0x0028, 0x0200). This tag contains the + // "Image Location" tag (0x0028, 0x0200). This tag contains the // the group that contains the pixel data (hence the "Pixel Data" // is found by indirection through the "Image Location"). // Inside the group pointed by "Image Location" the searched element @@ -543,7 +563,8 @@ size_t gdcmHeader::GetPixelOffset(void) { // When the "Image Location" is absent we default to group 0x7fe0. guint16 grPixel; guint16 numPixel; - std::string ImageLocation = GetPubElValByNumber(0x0028, 0x0200); + std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200); + if ( ImageLocation == GDCM_UNFOUND ) { // Image Location grPixel = 0x7fe0; } else { @@ -555,8 +576,7 @@ size_t gdcmHeader::GetPixelOffset(void) { else numPixel = 0x0010; - gdcmElValue* PixelElement = PubElValSet.GetElementByNumber(grPixel, - numPixel); + gdcmHeaderEntry* PixelElement = GetHeaderEntryByNumber(grPixel,numPixel); if (PixelElement) return PixelElement->GetOffset(); else @@ -565,7 +585,8 @@ size_t gdcmHeader::GetPixelOffset(void) { /** * \ingroup gdcmHeader - * \brief Recover the pixel area length (in Bytes) . + * \brief Recover the pixel area length (in Bytes) + * @return 0 by default. NOT USABLE file. The caller has to check. */ size_t gdcmHeader::GetPixelAreaLength(void) { // If this file complies with the norm we should encounter the @@ -577,7 +598,7 @@ size_t gdcmHeader::GetPixelAreaLength(void) { // When the "Image Location" is absent we default to group 0x7fe0. guint16 grPixel; guint16 numPixel; - std::string ImageLocation = GetPubElValByNumber(0x0028, 0x0200); + std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200); if ( ImageLocation == GDCM_UNFOUND ) { grPixel = 0x7fe0; } else { @@ -589,8 +610,7 @@ size_t gdcmHeader::GetPixelAreaLength(void) { else numPixel = 0x0010; - gdcmElValue* PixelElement = PubElValSet.GetElementByNumber(grPixel, - numPixel); + gdcmHeaderEntry* PixelElement = GetHeaderEntryByNumber(grPixel,numPixel); if (PixelElement) return PixelElement->GetLength(); else @@ -600,29 +620,29 @@ size_t gdcmHeader::GetPixelAreaLength(void) { /** * \ingroup gdcmHeader * \brief tells us if LUT are used - * \warning Right now, Segmented xxx Palette Color Lookup Table Data + * \warning Right now, 'Segmented xxx Palette Color Lookup Table Data' * \ are NOT considered as LUT, since nobody knows - *\ how to deal with them - * @return int acts as a Boolean + * \ how to deal with them + * @return a Boolean */ bool gdcmHeader::HasLUT(void) { // Check the presence of the LUT Descriptors - if (GetPubElValByNumber(0x0028,0x1101) == GDCM_UNFOUND) + if ( !GetHeaderEntryByNumber(0x0028,0x1101) ) return false; // LutDescriptorGreen - if (GetPubElValByNumber(0x0028,0x1102) == GDCM_UNFOUND) + if ( !GetHeaderEntryByNumber(0x0028,0x1102) ) return false; // LutDescriptorBlue - if (GetPubElValByNumber(0x0028,0x1103) == GDCM_UNFOUND) + if ( !GetHeaderEntryByNumber(0x0028,0x1103) ) return false; // It is not enough // we check also - if (GetPubElValByNumber(0x0028,0x1201) == GDCM_UNFOUND) + if ( !GetHeaderEntryByNumber(0x0028,0x1201) ) return false; - if (GetPubElValByNumber(0x0028,0x1202) == GDCM_UNFOUND) + if ( !GetHeaderEntryByNumber(0x0028,0x1202) ) return false; - if (GetPubElValByNumber(0x0028,0x1203) == GDCM_UNFOUND) + if ( !GetHeaderEntryByNumber(0x0028,0x1203) ) return false; return true; } @@ -631,7 +651,7 @@ bool gdcmHeader::HasLUT(void) { * \ingroup gdcmHeader * \brief gets the info from 0028,1101 : Lookup Table Desc-Red * \ else 0 - * @return Lookup Table nBit + * @return Lookup Table number of Bits , 0 by default * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ] */ int gdcmHeader::GetLUTNbits(void) { @@ -641,7 +661,7 @@ int gdcmHeader::GetLUTNbits(void) { int LutNbits; //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red = Lookup Table Desc-Blue // Consistency already checked in GetLUTLength - std::string LutDescription = GetPubElValByNumber(0x0028,0x1101); + std::string LutDescription = GetEntryByNumber(0x0028,0x1101); if (LutDescription == GDCM_UNFOUND) return 0; tokens.erase(tokens.begin(),tokens.end()); // clean any previous value @@ -666,32 +686,30 @@ int gdcmHeader::GetLUTNbits(void) { * \ 0028 1221 Segmented Red Palette Color Lookup Table Data * \ 0028 1222 Segmented Green Palette Color Lookup Table Data * \ 0028 1223 Segmented Blue Palette Color Lookup Table Data - * \ no known Dicom reader deails with them :-( - * @return Lookup Table RGBA + * \ no known Dicom reader deals with them :-( + * @return a RGBA Lookup Table */ unsigned char * gdcmHeader::GetLUTRGBA(void) { // Not so easy : see // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables -// and OT-PAL-8-face.dcm // if Photometric Interpretation # PALETTE COLOR, no LUT to be done - if (gdcmHeader::GetPubElValByNumber(0x0028,0x0004) != "PALETTE COLOR ") { + if (gdcmHeader::GetEntryByNumber(0x0028,0x0004) != "PALETTE COLOR ") { return NULL; } - int lengthR, debR, nbitsR; int lengthG, debG, nbitsG; int lengthB, debB, nbitsB; // Get info from Lut Descriptors // (the 3 LUT descriptors may be different) - std::string LutDescriptionR = GetPubElValByNumber(0x0028,0x1101); + std::string LutDescriptionR = GetEntryByNumber(0x0028,0x1101); if (LutDescriptionR == GDCM_UNFOUND) return NULL; - std::string LutDescriptionG = GetPubElValByNumber(0x0028,0x1102); + std::string LutDescriptionG = GetEntryByNumber(0x0028,0x1102); if (LutDescriptionG == GDCM_UNFOUND) return NULL; - std::string LutDescriptionB = GetPubElValByNumber(0x0028,0x1103); + std::string LutDescriptionB = GetEntryByNumber(0x0028,0x1103); if (LutDescriptionB == GDCM_UNFOUND) return NULL; @@ -720,11 +738,11 @@ unsigned char * gdcmHeader::GetLUTRGBA(void) { // Load LUTs into memory, (as they were stored on disk) unsigned char *lutR = (unsigned char *) - GetPubElValVoidAreaByNumber(0x0028,0x1201); + GetPubEntryVoidAreaByNumber(0x0028,0x1201); unsigned char *lutG = (unsigned char *) - GetPubElValVoidAreaByNumber(0x0028,0x1202); + GetPubEntryVoidAreaByNumber(0x0028,0x1202); unsigned char *lutB = (unsigned char *) - GetPubElValVoidAreaByNumber(0x0028,0x1203); + GetPubEntryVoidAreaByNumber(0x0028,0x1203); if (!lutR || !lutG || !lutB ) { return NULL; @@ -738,7 +756,7 @@ unsigned char * gdcmHeader::GetLUTRGBA(void) { memset(LUTRGBA, 0, 1024); // Bits Allocated int nb; - std::string str_nb = GetPubElValByNumber(0x0028,0x0100); + std::string str_nb = GetEntryByNumber(0x0028,0x0100); if (str_nb == GDCM_UNFOUND ) { nb = 16; } else { @@ -783,7 +801,7 @@ unsigned char * gdcmHeader::GetLUTRGBA(void) { //How to free the now useless LUTs? -//free(LutR); free(LutB); free(LutG); +//free(LutR); free(LutB); free(LutG); // Seg Fault when used return(LUTRGBA); } @@ -795,7 +813,7 @@ unsigned char * gdcmHeader::GetLUTRGBA(void) { */ std::string gdcmHeader::GetTransfertSyntaxName(void) { // use the gdcmTS (TS : Transfert Syntax) - std::string TransfertSyntax = GetPubElValByNumber(0x0002,0x0010); + std::string TransfertSyntax = GetEntryByNumber(0x0002,0x0010); if (TransfertSyntax == GDCM_UNFOUND) { dbg.Verbose(0, "gdcmHeader::GetTransfertSyntaxName: unfound Transfert Syntax (0002,0010)"); return "Uncompressed ACR-NEMA"; @@ -809,23 +827,23 @@ std::string gdcmHeader::GetTransfertSyntaxName(void) { /** * \ingroup gdcmHeader - * \brief Searches within the public dictionary for element value of + * \brief Searches within the file Header for element value of * a given tag. * @param tagName name of the searched element. * @return Corresponding element value when it exists, and the string * GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -std::string gdcmHeader::GetPubElValByName(std::string tagName) { +std::string gdcmHeader::GetPubEntryByName(std::string tagName) { gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); if( dictEntry == NULL) return GDCM_UNFOUND; - return(PubElValSet.GetElValueByNumber(dictEntry->GetGroup(), - dictEntry->GetElement())); + + return(GetEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement())); } /** * \ingroup gdcmHeader - * \brief Searches within the elements parsed with the public dictionary for + * \brief Searches within the elements parsed with the file Header for * the element value representation of a given tag. * * Obtaining the VR (Value Representation) might be needed by caller @@ -836,13 +854,13 @@ std::string gdcmHeader::GetPubElValByName(std::string tagName) { * @return Corresponding element value representation when it exists, * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -std::string gdcmHeader::GetPubElValRepByName(std::string tagName) { +std::string gdcmHeader::GetPubEntryVRByName(std::string tagName) { gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); if( dictEntry == NULL) - return GDCM_UNFOUND; - gdcmElValue* elem = PubElValSet.GetElementByNumber( - dictEntry->GetGroup(), - dictEntry->GetElement()); + return GDCM_UNFOUND; + + gdcmHeaderEntry* elem = GetHeaderEntryByNumber(dictEntry->GetGroup(), + dictEntry->GetElement()); return elem->GetVR(); } @@ -855,8 +873,8 @@ std::string gdcmHeader::GetPubElValRepByName(std::string tagName) { * @return Corresponding element value when it exists, and the string * GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -std::string gdcmHeader::GetPubElValByNumber(guint16 group, guint16 element) { - return PubElValSet.GetElValueByNumber(group, element); +std::string gdcmHeader::GetPubEntryByNumber(guint16 group, guint16 element) { + return PubEntrySet.GetEntryByNumber(group, element); } /** @@ -873,8 +891,8 @@ std::string gdcmHeader::GetPubElValByNumber(guint16 group, guint16 element) { * @return Corresponding element value representation when it exists, * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -std::string gdcmHeader::GetPubElValRepByNumber(guint16 group, guint16 element) { - gdcmElValue* elem = PubElValSet.GetElementByNumber(group, element); +std::string gdcmHeader::GetPubEntryVRByNumber(guint16 group, guint16 element) { + gdcmHeaderEntry* elem = GetHeaderEntryByNumber(group, element); if ( !elem ) return GDCM_UNFOUND; return elem->GetVR(); @@ -882,44 +900,46 @@ std::string gdcmHeader::GetPubElValRepByNumber(guint16 group, guint16 element) { /** * \ingroup gdcmHeader - * \brief Accesses an existing gdcmElValue in the PubElValSet of this instance + * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element) + * in the PubHeaderEntrySet 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 + * @param tagName name of the Header Entry (Dicom Element) to be modified */ -bool gdcmHeader::SetPubElValByName(std::string content, std::string tagName) { - //return ( PubElValSet.SetElValueByName (content, tagName) ); +bool gdcmHeader::SetPubEntryByName(std::string content, std::string tagName) { + //return ( PubHeaderEntrySet.SetHeaderEntryByName (content, tagName) ); gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); if( dictEntry == NULL) - return false; - return(PubElValSet.SetElValueByNumber(content, - dictEntry->GetGroup(), - dictEntry->GetElement())); + return false; + return(PubEntrySet.SetEntryByNumber(content, + dictEntry->GetGroup(), + dictEntry->GetElement())); } /** * \ingroup gdcmHeader - * \brief Accesses an existing gdcmElValue (i.e. a Dicom Element) - * in the PubElValSet of this instance + * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element) + * in the PubHeaderEntrySet 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 Dicom Element to modify * @param element element of the Dicom Element to modify */ -bool gdcmHeader::SetPubElValByNumber(std::string content, guint16 group, +bool gdcmHeader::SetPubEntryByNumber(std::string content, guint16 group, guint16 element) //TODO : homogeneiser les noms : SetPubElValByNumber -// qui appelle PubElValSet.SetElValueByNumber -// pourquoi pas SetPubElValueByNumber ?? +// qui appelle PubHeaderEntrySet.SetHeaderEntryByNumber +// pourquoi pas SetPubHeaderEntryByNumber ?? { - return ( PubElValSet.SetElValueByNumber (content, group, element) ); + return ( PubEntrySet.SetEntryByNumber (content, group, element) ); } /** * \ingroup gdcmHeader - * \brief Accesses an existing gdcmElValue in the PubElValSet of this instance + * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element) + * in the PubHeaderEntrySet of this instance * through it's (group, element) and modifies it's length with * the given value. * \warning Use with extreme caution. @@ -929,29 +949,28 @@ bool gdcmHeader::SetPubElValByNumber(std::string content, guint16 group, * @return 1 on success, 0 otherwise. */ -bool gdcmHeader::SetPubElValLengthByNumber(guint32 length, guint16 group, +bool gdcmHeader::SetPubEntryLengthByNumber(guint32 length, guint16 group, guint16 element) { - return ( PubElValSet.SetElValueLengthByNumber (length, group, element) ); + return ( PubEntrySet.SetEntryLengthByNumber (length, group, element) ); } /** * \ingroup gdcmHeader - * \brief Searches within elements parsed with the public dictionary - * and then within the elements parsed with the shadow dictionary + * \brief Searches within Header Entries (Dicom Elements) parsed with + * the public and private dictionaries * for the element value of a given tag. * @param tagName name of the searched element. * @return Corresponding element value when it exists, * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -std::string gdcmHeader::GetElValByName(std::string tagName) { - std::string pub = GetPubElValByName(tagName); - return pub; +std::string gdcmHeader::GetEntryByName(std::string tagName) { + return GetPubEntryByName(tagName); } /** * \ingroup gdcmHeader - * \brief Searches within elements parsed with the public dictionary - * and then within the elements parsed with the shadow dictionary + * \brief Searches within Header Entries (Dicom Elements) parsed with + * the public and private dictionaries * for the element value representation of a given tag. * * Obtaining the VR (Value Representation) might be needed by caller @@ -962,31 +981,29 @@ std::string gdcmHeader::GetElValByName(std::string tagName) { * @return Corresponding element value representation when it exists, * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -std::string gdcmHeader::GetElValRepByName(std::string tagName) { - std::string pub = GetPubElValRepByName(tagName); - return pub; +std::string gdcmHeader::GetEntryVRByName(std::string tagName) { + return GetPubEntryVRByName(tagName); } /** * \ingroup gdcmHeader - * \brief Searches within elements parsed with the public dictionary - * and then within the elements parsed with the shadow dictionary - * for the element value of a given tag. + * \brief Searches within Header Entries (Dicom Elements) parsed with + * the public and private dictionaries + * for the element value representation of a given tag. * @param group Group of the searched tag. * @param element Element of the searched tag. * @return Corresponding element value representation when it exists, * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -std::string gdcmHeader::GetElValByNumber(guint16 group, guint16 element) { - std::string pub = GetPubElValByNumber(group, element); - return pub; +std::string gdcmHeader::GetEntryByNumber(guint16 group, guint16 element) { + return GetPubEntryByNumber(group, element); } /** * \ingroup gdcmHeader - * \brief Searches within elements parsed with the public dictionary - * and then within the elements parsed with the shadow dictionary - * for the element value representation of a given tag. + * \brief Searches within Header Entries (Dicom Elements) parsed with + * the public and private dictionaries + * for the element value representation of a given tag.. * * Obtaining the VR (Value Representation) might be needed by caller * to convert the string typed content to caller's native type @@ -997,21 +1014,18 @@ std::string gdcmHeader::GetElValByNumber(guint16 group, guint16 element) { * @return Corresponding element value representation when it exists, * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. */ -std::string gdcmHeader::GetElValRepByNumber(guint16 group, guint16 element) { - std::string pub = GetPubElValRepByNumber(group, element); - return pub; +std::string gdcmHeader::GetEntryVRByNumber(guint16 group, guint16 element) { + return GetPubEntryVRByNumber(group, element); } /** - * \ingroup gdcmElValSet - * \brief Sets the value (string) of the target Dicom Element + * \ingroup gdcmHeader + * \brief Sets the value (string) of the Header Entry (Dicom Element) * @param content string value of the Dicom Element * @param tagName name of the searched Dicom Element. * @return true when found */ -bool gdcmHeader::SetElValueByName(std::string content, - std::string tagName) { - +bool gdcmHeader::SetEntryByName(std::string content,std::string tagName) { gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); if( dictEntry == NULL) return false; @@ -1019,7 +1033,7 @@ bool gdcmHeader::SetElValueByName(std::string content, TagKey key = gdcmDictEntry::TranslateToKey(dictEntry->GetGroup(), dictEntry->GetElement()); - if ( ! PubElValSet.GetTagHt().count(key)) + if ( PubEntrySet.GetTagHT().count(key) == 0 ) return false; int l = content.length(); if(l%2) { // Odd length are padded with a space (020H). @@ -1028,20 +1042,16 @@ bool gdcmHeader::SetElValueByName(std::string content, } //tagHt[key]->SetValue(content); - gdcmElValue * a; + gdcmHeaderEntry * a; IterHT p; - TagElValueHT::iterator p2; - // DO NOT remove the following lines : they explain the stuff + TagHeaderEntryHT::iterator p2; + // DO NOT remove the following lines : they explain how the stuff works //p= tagHt.equal_range(key); // get a pair of iterators first-last synonym //p2=p.first; // iterator on the first synonym - //a=p2->second; // H Table target column (2-nd col) - + //a=p2->second; // H Table target column (2-nd col) // or, easier : - a = ((PubElValSet.GetTagHt().equal_range(key)).first)->second; - - a-> SetValue(content); - - //std::string vr = tagHt[key]->GetVR(); + a = ((PubEntrySet.GetTagHT().equal_range(key)).first)->second; + a-> SetValue(content); std::string vr = a->GetVR(); guint32 lgr; @@ -1051,14 +1061,13 @@ bool gdcmHeader::SetElValueByName(std::string content, lgr = 4; else lgr = l; - //tagHt[key]->SetLength(lgr); a->SetLength(lgr); return true; } /** * \ingroup gdcmHeader - * \brief + * \brief opens the file * @param exception_on_error * @return */ @@ -1074,7 +1083,7 @@ FILE *gdcmHeader::OpenFile(bool exception_on_error) guint16 zero; fread(&zero, (size_t)2, (size_t)1, fp); - //ACR -- or DICOM with no Preamble + //ACR -- or DICOM with no Preamble -- if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200) return(fp); @@ -1096,7 +1105,7 @@ FILE *gdcmHeader::OpenFile(bool exception_on_error) /** * \ingroup gdcmHeader - * \brief + * \brief closes the file * @return TRUE if the close was successfull */ bool gdcmHeader::CloseFile(void) { @@ -1112,20 +1121,22 @@ bool gdcmHeader::CloseFile(void) { * \brief Parses the header of the file but WITHOUT loading element values. */ void gdcmHeader::ParseHeader(bool exception_on_error) throw(gdcmFormatError) { - gdcmElValue * newElValue = (gdcmElValue *)0; + gdcmHeaderEntry * newHeaderEntry = (gdcmHeaderEntry *)0; rewind(fp); CheckSwap(); - while ( (newElValue = ReadNextElement()) ) { - SkipElementValue(newElValue); - PubElValSet.Add(newElValue); + while ( (newHeaderEntry = ReadNextHeaderEntry()) ) { + SkipHeaderEntry(newHeaderEntry); + PubEntrySet.Add(newHeaderEntry); } } /** * \ingroup gdcmHeader - * \brief - * @return integer, acts as a Boolean + * \brief + * @param fp file pointer on an already open file + * @param type file type ( ImplicitVR, ExplicitVR, ...) + * @return Boolean */ bool gdcmHeader::Write(FILE * fp, FileType type) { @@ -1140,7 +1151,7 @@ bool gdcmHeader::Write(FILE * fp, FileType type) { // values with a VR of UI shall be padded with a single trailing null // Dans le cas suivant on doit pader manuellement avec un 0 - PubElValSet.SetElValueLengthByNumber(18, 0x0002, 0x0010); + PubEntrySet.SetEntryLengthByNumber(18, 0x0002, 0x0010); } if (type == ExplicitVR) { @@ -1151,10 +1162,10 @@ bool gdcmHeader::Write(FILE * fp, FileType type) { // values with a VR of UI shall be padded with a single trailing null // Dans le cas suivant on doit pader manuellement avec un 0 - PubElValSet.SetElValueLengthByNumber(20, 0x0002, 0x0010); + PubEntrySet.SetEntryLengthByNumber(20, 0x0002, 0x0010); } - return PubElValSet.Write(fp, type); + return PubEntrySet.Write(fp, type); } /** @@ -1171,18 +1182,76 @@ bool gdcmHeader::Write(FILE * fp, FileType type) { void gdcmHeader::SetImageDataSize(size_t ImageDataSize) { std::string content1; char car[20]; - // Assumes ElValue (0x7fe0, 0x0010) exists ... + // Assumes HeaderEntry (0x7fe0, 0x0010) exists ... sprintf(car,"%d",ImageDataSize); - gdcmElValue *a = GetElValueByNumber(0x7fe0, 0x0010); + gdcmHeaderEntry *a = GetHeaderEntryByNumber(0x7fe0, 0x0010); a->SetLength(ImageDataSize); ImageDataSize+=8; sprintf(car,"%d",ImageDataSize); content1=car; - SetPubElValByNumber(content1, 0x7fe0, 0x0000); + SetPubEntryByNumber(content1, 0x7fe0, 0x0000); } +/** + * \ingroup gdcmHeader + * \brief Modifies the value of a given Header Entry (Dicom Element) + * if it exists; Creates it with the given value if it doesn't + * @param Value passed as a std::string + * @param Group + * @param Elem + * \return boolean + */ +bool gdcmHeader::ReplaceOrCreateByNumber(std::string Value, + guint16 Group, guint16 Elem ) { + + if (CheckIfExistByNumber(Group, Elem) == 0) { + gdcmHeaderEntry* a =NewHeaderEntryByNumber(Group, Elem); + if (a == NULL) + return false; + PubEntrySet.Add(a); + } + PubEntrySet.SetEntryByNumber(Value, Group, Elem); + return(true); +} + +/** + * \ingroup gdcmHeader + * \brief Modifies the value of a given Header Entry (Dicom Element) + * if it exists; Creates it with the given value if it doesn't + * @param Value passed as a char* + * @param Group + * @param Elem + * \return boolean + * + */ +bool gdcmHeader::ReplaceOrCreateByNumber(char* Value, guint16 Group, guint16 Elem ) { + + gdcmHeaderEntry* nvHeaderEntry=NewHeaderEntryByNumber(Group, Elem); + // TODO : check if fails + PubEntrySet.Add(nvHeaderEntry); + std::string v = Value; + PubEntrySet.SetEntryByNumber(v, Group, Elem); + return(true); +} + +/** + * \ingroup gdcmHeader + * \brief Set a new value if the invoked element exists + * Seems to be useless !!! + * @param Value + * @param Group + * @param Elem + * \return integer acts as a boolean + */ +bool gdcmHeader::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem ) { + + std::string v = Value; + PubEntrySet.SetEntryByNumber(v, Group, Elem); + return true; +} + /** * \ingroup gdcmHeader * \brief Swaps back the bytes of 4-byte long integer accordingly to @@ -1231,63 +1300,78 @@ guint16 gdcmHeader::SwapShort(guint16 a) { * * @return */ -gdcmElValue* gdcmHeader::GetElValueByNumber(guint16 Group, guint16 Elem) { - - gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); - if (!elValue) { - dbg.Verbose(1, "gdcmHeader::GetElValueByNumber", - "failed to Locate gdcmElValue"); - return (gdcmElValue*)0; +gdcmHeaderEntry *gdcmHeader::GetHeaderEntryByNumber(guint16 Group, guint16 Elem) { + gdcmHeaderEntry *HeaderEntry = PubEntrySet.GetHeaderEntryByNumber(Group, Elem); + if (!HeaderEntry) { + dbg.Verbose(1, "gdcmHeader::GetHeaderEntryByNumber", + "failed to Locate gdcmHeaderEntry"); + return NULL; } - return elValue; + return HeaderEntry; +} + +/** + * \ingroup gdcmHeader + * \brief Searches within the Header Entries for a Dicom Element of + * a given tag. + * @param tagName name of the searched Dicom Element. + * @return Corresponding Dicom Element when it exists, and NULL + * otherwise. + */ + gdcmHeaderEntry *gdcmHeader::GetHeaderEntryByName(std::string tagName) { + gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); + if( dictEntry == NULL) + return NULL; + + return(GetHeaderEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement())); } /** * \ingroup gdcmHeader - * \brief Checks if a given ElValue (group,number) - * \ exists in the Public ElValSet + * \brief Checks if a given HeaderEntry (group,number) + * \ exists in the Public HeaderEntrySet * @param Group * @param Elem - * @return integer acts as a boolean + * @return boolean */ bool gdcmHeader::CheckIfExistByNumber(guint16 Group, guint16 Elem ) { - return (PubElValSet.CheckIfExistByNumber(Group, Elem)); + return (PubEntrySet.CheckIfExistByNumber(Group, Elem)>0); } /** * \ingroup gdcmHeader * \brief Gets (from Header) the offset of a 'non string' element value - * \ (LoadElementValue has already be executed) + * \ (LoadElementValues has already be executed) * @param Group * @param Elem * @return File Offset of the Element Value */ -size_t gdcmHeader::GetPubElValOffsetByNumber(guint16 Group, guint16 Elem) { - gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); - if (!elValue) { - dbg.Verbose(1, "gdcmHeader::GetElValueByNumber", - "failed to Locate gdcmElValue"); +size_t gdcmHeader::GetPubEntryOffsetByNumber(guint16 Group, guint16 Elem) { + gdcmHeaderEntry* Entry = GetHeaderEntryByNumber(Group, Elem); + if (!Entry) { + dbg.Verbose(1, "gdcmHeader::GetHeaderEntryByNumber", + "failed to Locate gdcmHeaderEntry"); return (size_t)0; } - return elValue->GetOffset(); + return Entry->GetOffset(); } /** * \ingroup gdcmHeader * \brief Gets (from Header) a 'non string' element value - * \ (LoadElementValue has already be executed) + * \ (LoadElementValues has already be executed) * @param Group * @param Elem * @return Pointer to the 'non string' area */ -void * gdcmHeader::GetPubElValVoidAreaByNumber(guint16 Group, guint16 Elem) { - gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); - if (!elValue) { - dbg.Verbose(1, "gdcmHeader::GetElValueByNumber", - "failed to Locate gdcmElValue"); +void * gdcmHeader::GetPubEntryVoidAreaByNumber(guint16 Group, guint16 Elem) { + gdcmHeaderEntry* Entry = GetHeaderEntryByNumber(Group, Elem); + if (!Entry) { + dbg.Verbose(1, "gdcmHeader::GetHeaderEntryByNumber", + "failed to Locate gdcmHeaderEntry"); return (NULL); } - return elValue->GetVoidArea(); + return Entry->GetVoidArea(); } /** @@ -1295,8 +1379,8 @@ void * gdcmHeader::GetPubElValVoidAreaByNumber(guint16 Group, guint16 Elem) { * \brief Loads (from disk) the element content * when a string is not suitable */ -void * gdcmHeader::LoadElementVoidArea(guint16 Group, guint16 Elem) { - gdcmElValue * Element= PubElValSet.GetElementByNumber(Group, Elem); +void * gdcmHeader::LoadEntryVoidArea(guint16 Group, guint16 Elem) { + gdcmHeaderEntry * Element= GetHeaderEntryByNumber(Group, Elem); if ( !Element ) return NULL; size_t o =(size_t)Element->GetOffset(); @@ -1306,7 +1390,8 @@ void * gdcmHeader::LoadElementVoidArea(guint16 Group, guint16 Elem) { if(!a) { return NULL; } - /* int res = */ PubElValSet.SetVoidAreaByNumber(a, Group, Elem); + + PubEntrySet.SetVoidAreaByNumber(a, Group, Elem); // TODO check the result size_t l2 = fread(a, 1, l ,fp); if(l != l2) { @@ -1316,105 +1401,34 @@ void * gdcmHeader::LoadElementVoidArea(guint16 Group, guint16 Elem) { return a; } -/** - * \ingroup gdcmHeader - * \brief TODO - * @param Value - * @param Group - * @param Elem - * \return integer acts as a boolean - */ -bool gdcmHeader::ReplaceOrCreateByNumber(std::string Value, - guint16 Group, guint16 Elem ) { - // TODO : FIXME JPRx - // curieux, non ? - // on (je) cree une Elvalue ne contenant pas de valeur - // on l'ajoute au ElValSet - // on affecte une valeur a cette ElValue a l'interieur du ElValSet - // --> devrait pouvoir etre fait + simplement ??? - if (CheckIfExistByNumber(Group, Elem) == 0) { - gdcmElValue* a =NewElValueByNumber(Group, Elem); - if (a == NULL) - return false; - PubElValSet.Add(a); - } - PubElValSet.SetElValueByNumber(Value, Group, Elem); - return(true); -} - -/** - * \ingroup gdcmHeader - * \brief Modify (or Creates if not found) an element - * @param Value new value - * @param Group - * @param Elem - * \return integer acts as a boolean - * - */ -bool gdcmHeader::ReplaceOrCreateByNumber(char* Value, guint16 Group, guint16 Elem ) { - - gdcmElValue* nvElValue=NewElValueByNumber(Group, Elem); - // TODO : check if fails - PubElValSet.Add(nvElValue); - std::string v = Value; - PubElValSet.SetElValueByNumber(v, Group, Elem); - return(true); -} - -/** - * \ingroup gdcmHeader - * \brief Set a new value if the invoked element exists - * Seems to be useless !!! - * @param Value - * @param Group - * @param Elem - * \return integer acts as a boolean - */ -bool gdcmHeader::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem ) { - - //gdcmElValue* elValue = PubElValSet.GetElementByNumber(Group, Elem); - std::string v = Value; - PubElValSet.SetElValueByNumber(v, Group, Elem); - return true; -} - //----------------------------------------------------------------------------- // Private /** * \ingroup gdcmHeader - * \brief Loads the element values of all the elements present in the - * public tag based hash table. + * \brief Loads the element values of all the Header Entries pointed in the + * public Chained List. */ -void gdcmHeader::LoadElements(void) { +void gdcmHeader::LoadHeaderEntries(void) { rewind(fp); - - // We don't use any longer the HashTable, since a lot a stuff is missing - // when SeQuences were encountered - // - //TagElValueHT ht = PubElValSet.GetTagHt(); - //for (TagElValueHT::iterator tag = ht.begin(); tag != ht.end(); ++tag) { - // LoadElementValue(tag->second); - //} - - for (ListTag::iterator i = GetPubListElem().begin(); - i != GetPubListElem().end(); - ++i){ - LoadElementValue(*i); - } - + for (ListTag::iterator i = GetPubListEntry().begin(); + i != GetPubListEntry().end(); + ++i){ + LoadHeaderEntry(*i); + } + rewind(fp); // Load 'non string' values - std::string PhotometricInterpretation = GetPubElValByNumber(0x0028,0x0004); + std::string PhotometricInterpretation = GetPubEntryByNumber(0x0028,0x0004); if( PhotometricInterpretation == "PALETTE COLOR " ){ - LoadElementVoidArea(0x0028,0x1200); // gray LUT - LoadElementVoidArea(0x0028,0x1201); // R LUT - LoadElementVoidArea(0x0028,0x1202); // G LUT - LoadElementVoidArea(0x0028,0x1203); // B LUT + LoadEntryVoidArea(0x0028,0x1200); // gray LUT + LoadEntryVoidArea(0x0028,0x1201); // R LUT + LoadEntryVoidArea(0x0028,0x1202); // G LUT + LoadEntryVoidArea(0x0028,0x1203); // B LUT - LoadElementVoidArea(0x0028,0x1221); // Segmented Red Palette Color LUT Data - LoadElementVoidArea(0x0028,0x1222); // Segmented Green Palette Color LUT Data - LoadElementVoidArea(0x0028,0x1223); // Segmented Blue Palette Color LUT Data + LoadEntryVoidArea(0x0028,0x1221); // Segmented Red Palette Color LUT Data + LoadEntryVoidArea(0x0028,0x1222); // Segmented Green Palette Color LUT Data + LoadEntryVoidArea(0x0028,0x1223); // Segmented Blue Palette Color LUT Data } // -------------------------------------------------------------- @@ -1424,14 +1438,14 @@ void gdcmHeader::LoadElements(void) { // we switch lineNumber and columnNumber // std::string RecCode; - RecCode = GetPubElValByNumber(0x0008, 0x0010); + RecCode = GetPubEntryByNumber(0x0008, 0x0010); // recognition code if (RecCode == "ACRNEMA_LIBIDO_1.1" || RecCode == "CANRME_AILIBOD1_1." ) { filetype = ACR_LIBIDO; - std::string rows = GetPubElValByNumber(0x0028, 0x0010); - std::string columns = GetPubElValByNumber(0x0028, 0x0011); - SetPubElValByNumber(columns, 0x0028, 0x0010); - SetPubElValByNumber(rows , 0x0028, 0x0011); + std::string rows = GetPubEntryByNumber(0x0028, 0x0010); + std::string columns = GetPubEntryByNumber(0x0028, 0x0011); + SetPubEntryByNumber(columns, 0x0028, 0x0010); + SetPubEntryByNumber(rows , 0x0028, 0x0011); } // ----------------- End of Special Patch ---------------- } @@ -1441,9 +1455,9 @@ void gdcmHeader::LoadElements(void) { * \brief Loads the element content if it's length is not bigger * than the value specified with * gdcmHeader::SetMaxSizeLoadElementValue() - * @param ElVal string value of the Dicom Element + * @param ElVal Header Entry (Dicom Element) to be dealt with */ -void gdcmHeader::LoadElementValue(gdcmElValue * ElVal) { +void gdcmHeader::LoadHeaderEntry(gdcmHeaderEntry * ElVal) { size_t item_read; guint16 group = ElVal->GetGroup(); std::string vr= ElVal->GetVR(); @@ -1455,7 +1469,7 @@ void gdcmHeader::LoadElementValue(gdcmElValue * ElVal) { // the test was commented out to 'go inside' the SeQuences // we don't any longer skip them ! - // if( vr == "SQ" ) + // if( vr == "SQ" ) // (DO NOT remove this comment) // SkipLoad = true; // A SeQuence "contains" a set of Elements. @@ -1490,13 +1504,14 @@ void gdcmHeader::LoadElementValue(gdcmElValue * ElVal) { return; } - // When an integer is expected, read and convert the following two or - // four bytes properly i.e. as an integer as opposed to a string. - - // Actually, elements with Value Multiplicity > 1 - // contain a set of integers (not a single one) - // Any compacter code suggested (?) - if ( IsAnInteger(ElVal) ) { + // When integer(s) are expected, read and convert the following + // n *(two or four bytes) + // properly i.e. as integers as opposed to a strings. + // Elements with Value Multiplicity > 1 + // contain a set of integers (not a single one) + + // Any compacter code suggested (?) + if ( IsHeaderEntryAnInteger(ElVal) ) { guint32 NewInt; std::ostringstream s; int nbInt; @@ -1554,23 +1569,24 @@ void gdcmHeader::LoadElementValue(gdcmElValue * ElVal) { * \ingroup gdcmHeader * \brief Loads the element while preserving the current * underlying file position indicator as opposed to - * to LoadElementValue that modifies it. - * @param ElVal Element whose value shall be loaded. + * to LoadHeaderEntry that modifies it. + * @param entry Header Entry whose value shall be loaded. * @return */ -void gdcmHeader::LoadElementValueSafe(gdcmElValue * ElVal) { +void gdcmHeader::LoadHeaderEntrySafe(gdcmHeaderEntry * entry) { long PositionOnEntry = ftell(fp); - LoadElementValue(ElVal); + LoadHeaderEntry(entry); fseek(fp, PositionOnEntry, SEEK_SET); } /** * \ingroup gdcmHeader * \brief - * + * @param entry Header Entry whose value shall be loaded. + * @return */ - void gdcmHeader::FindLength (gdcmElValue * ElVal) { + void gdcmHeader::FindHeaderEntryLength (gdcmHeaderEntry * ElVal) { guint16 element = ElVal->GetElement(); guint16 group = ElVal->GetGroup(); std::string vr = ElVal->GetVR(); @@ -1592,10 +1608,10 @@ void gdcmHeader::LoadElementValueSafe(gdcmElValue * ElVal) { guint32 length32 = ReadInt32(); if ( (vr == "OB") && (length32 == 0xffffffff) ) { - ElVal->SetLength(FindLengthOB()); + ElVal->SetLength(FindHeaderEntryLengthOB()); return; } - FixFoundLength(ElVal, length32); + FixHeaderEntryFoundLength(ElVal, length32); return; } @@ -1661,7 +1677,7 @@ void gdcmHeader::LoadElementValueSafe(gdcmElValue * ElVal) { // Unknown Sequence Length } - FixFoundLength(ElVal, (guint32)length16); + FixHeaderEntryFoundLength(ElVal, (guint32)length16); return; } @@ -1671,16 +1687,16 @@ void gdcmHeader::LoadElementValueSafe(gdcmElValue * ElVal) { // on Data elements "Implicit and Explicit VR Data Elements shall // not coexist in a Data Set and Data Sets nested within it".] // Length is on 4 bytes. - FixFoundLength(ElVal, ReadInt32()); + FixHeaderEntryFoundLength(ElVal, ReadInt32()); return; } /** * \ingroup gdcmHeader - * \brief Find the value representation of the current tag. + * \brief Find the Value Representation of the current Dicom Element. * @param ElVal */ -void gdcmHeader::FindVR( gdcmElValue *ElVal) { +void gdcmHeader::FindHeaderEntryVR( gdcmHeaderEntry *ElVal) { if (filetype != ExplicitVR) return; @@ -1722,19 +1738,19 @@ void gdcmHeader::FindVR( gdcmElValue *ElVal) { if ( RealExplicit ) { if ( ElVal->IsVRUnknown() ) { - // When not a dictionary entry, we can safely overwrite the vr. + // When not a dictionary entry, we can safely overwrite the VR. ElVal->SetVR(vr); return; } if ( ElVal->GetVR() == vr ) { - // The vr we just read and the dictionary agree. Nothing to do. + // The VR we just read and the dictionary agree. Nothing to do. return; } - // The vr present in the file and the dictionary disagree. We assume - // the file writer knew best and use the vr of the file. Since it would - // be unwise to overwrite the vr of a dictionary (since it would + // The VR present in the file and the dictionary disagree. We assume + // the file writer knew best and use the VR of the file. Since it would + // be unwise to overwrite the VR of a dictionary (since it would // compromise it's next user), we need to clone the actual DictEntry - // and change the vr for the read one. + // and change the VR for the read one. gdcmDictEntry* NewTag = new gdcmDictEntry(ElVal->GetGroup(), ElVal->GetElement(), vr, @@ -1753,7 +1769,7 @@ void gdcmHeader::FindVR( gdcmElValue *ElVal) { fseek(fp, PositionOnEntry, SEEK_SET); // When this element is known in the dictionary we shall use, e.g. for - // the semantics (see the usage of IsAnInteger), the vr proposed by the + // the semantics (see the usage of IsAnInteger), the VR proposed by the // dictionary entry. Still we have to flag the element as implicit since // we know now our assumption on expliciteness is not furfilled. // avoid . @@ -1762,62 +1778,14 @@ void gdcmHeader::FindVR( gdcmElValue *ElVal) { ElVal->SetImplicitVr(); } -/** - * \ingroup gdcmHeader - * \brief - * - * @return - */ - guint32 gdcmHeader::FindLengthOB(void) { - // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. - guint16 g; - guint16 n; - long PositionOnEntry = ftell(fp); - bool FoundSequenceDelimiter = false; - guint32 TotalLength = 0; - guint32 ItemLength; - - 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 && g!=0xb00c ) /*for bogus header */ { - char msg[100]; // for sprintf. Sorry - sprintf(msg,"wrong group (%04x) for an item sequence (%04x,%04x)\n",g, g,n); - dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",msg); - errno = 1; - return 0; - } - if ( n == 0xe0dd || ( g==0xb00c && n==0x0eb6 ) ) /* for bogus header */ - FoundSequenceDelimiter = true; - else if ( n != 0xe000 ){ - char msg[100]; // for sprintf. Sorry - sprintf(msg,"wrong element (%04x) for an item sequence (%04x,%04x)\n", - n, g,n); - dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",msg); - errno = 1; - return 0; - } - ItemLength = ReadInt32(); - TotalLength += ItemLength + 4; // We add 4 bytes since we just read - // the ItemLength with ReadInt32 - SkipBytes(ItemLength); - } - fseek(fp, PositionOnEntry, SEEK_SET); - return TotalLength; -} - /** * \ingroup gdcmHeader * \brief * @param ElVal * @return */ -void gdcmHeader::SkipElementValue(gdcmElValue * ElVal) { - SkipBytes(ElVal->GetLength()); +void gdcmHeader::SkipHeaderEntry(gdcmHeaderEntry * entry) { + SkipBytes(entry->GetLength()); } /** @@ -1826,7 +1794,7 @@ void gdcmHeader::SkipElementValue(gdcmElValue * ElVal) { * the parser went Jabberwocky) one can hope improving things by * applying this heuristic. */ -void gdcmHeader::FixFoundLength(gdcmElValue * ElVal, guint32 FoundLength) { +void gdcmHeader::FixHeaderEntryFoundLength(gdcmHeaderEntry * ElVal, guint32 FoundLength) { ElVal->SetReadLength(FoundLength); // will be updated only if a bug is found @@ -1861,6 +1829,23 @@ void gdcmHeader::FixFoundLength(gdcmElValue * ElVal, guint32 FoundLength) { FoundLength =0; } + // a SeQuence Element is beginning + // Let's forget it's length + // (we want to 'go inside') + + // Pb : *normaly* fffe|e000 is just a marker, its length *should be* zero + // in gdcm-MR-PHILIPS-16-Multi-Seq.dcm we find lengthes as big as 28800 + // if we set the length to zero IsHeaderEntryAnInteger() breaks... + // if we don't, we lost 28800 characters from the Header :-( + + else if(ElVal->GetGroup() == 0xfffe){ + // sometimes, length seems to be wrong + FoundLength =0; // some more clever checking to be done ! + // I give up! + // only gdcm-MR-PHILIPS-16-Multi-Seq.dcm + // causes troubles :-( + } + ElVal->SetUsableLength(FoundLength); } @@ -1871,7 +1856,7 @@ void gdcmHeader::FixFoundLength(gdcmElValue * ElVal, guint32 FoundLength) { * @param ElVal The element value on which to apply the predicate. * @return The result of the heuristical predicate. */ -bool gdcmHeader::IsAnInteger(gdcmElValue * ElVal) { +bool gdcmHeader::IsHeaderEntryAnInteger(gdcmHeaderEntry * ElVal) { guint16 element = ElVal->GetElement(); guint16 group = ElVal->GetGroup(); std::string vr = ElVal->GetVR(); @@ -1897,6 +1882,54 @@ bool gdcmHeader::IsAnInteger(gdcmElValue * ElVal) { return false; } +/** + * \ingroup gdcmHeader + * \brief + * + * @return + */ + guint32 gdcmHeader::FindHeaderEntryLengthOB(void) { + // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. + guint16 g; + guint16 n; + long PositionOnEntry = ftell(fp); + bool FoundSequenceDelimiter = false; + guint32 TotalLength = 0; + guint32 ItemLength; + + 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 && g!=0xb00c ) /*for bogus header */ { + char msg[100]; // for sprintf. Sorry + sprintf(msg,"wrong group (%04x) for an item sequence (%04x,%04x)\n",g, g,n); + dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",msg); + errno = 1; + return 0; + } + if ( n == 0xe0dd || ( g==0xb00c && n==0x0eb6 ) ) /* for bogus header */ + FoundSequenceDelimiter = true; + else if ( n != 0xe000 ){ + char msg[100]; // for sprintf. Sorry + sprintf(msg,"wrong element (%04x) for an item sequence (%04x,%04x)\n", + n, g,n); + dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",msg); + errno = 1; + return 0; + } + ItemLength = ReadInt32(); + TotalLength += ItemLength + 4; // We add 4 bytes since we just read + // the ItemLength with ReadInt32 + SkipBytes(ItemLength); + } + fseek(fp, PositionOnEntry, SEEK_SET); + return TotalLength; +} + /** * \ingroup gdcmHeader * \brief Reads a supposed to be 16 Bits integer @@ -2243,12 +2276,12 @@ gdcmDictEntry * gdcmHeader::GetDictEntryByName(std::string Name) { /** * \ingroup gdcmHeader * \brief Read the next tag but WITHOUT loading it's value - * @return On succes the newly created ElValue, NULL on failure. + * @return On succes the newly created HeaderEntry, NULL on failure. */ -gdcmElValue * gdcmHeader::ReadNextElement(void) { +gdcmHeaderEntry * gdcmHeader::ReadNextHeaderEntry(void) { guint16 g,n; - gdcmElValue * NewElVal; + gdcmHeaderEntry * NewElVal; g = ReadInt16(); n = ReadInt16(); @@ -2256,15 +2289,15 @@ gdcmElValue * gdcmHeader::ReadNextElement(void) { if (errno == 1) // We reached the EOF (or an error occured) and header parsing // has to be considered as finished. - return (gdcmElValue *)0; + return (gdcmHeaderEntry *)0; - NewElVal = NewElValueByNumber(g, n); - FindVR(NewElVal); - FindLength(NewElVal); + NewElVal = NewHeaderEntryByNumber(g, n); + FindHeaderEntryVR(NewElVal); + FindHeaderEntryLength(NewElVal); if (errno == 1) { // Call it quits - return (gdcmElValue *)0; + return (gdcmHeaderEntry *)0; } NewElVal->SetOffset(ftell(fp)); //if ( (g==0x7fe0) && (n==0x0010) ) @@ -2278,17 +2311,17 @@ gdcmElValue * gdcmHeader::ReadNextElement(void) { * a default one when absent. * @param Name Name of the underlying DictEntry */ -gdcmElValue* gdcmHeader::NewElValueByName(std::string Name) { +gdcmHeaderEntry* gdcmHeader::NewHeaderEntryByName(std::string Name) { gdcmDictEntry * NewTag = GetDictEntryByName(Name); if (!NewTag) NewTag = new gdcmDictEntry(0xffff, 0xffff, "LO", "Unknown", Name); - gdcmElValue* NewElVal = new gdcmElValue(NewTag); + gdcmHeaderEntry* NewElVal = new gdcmHeaderEntry(NewTag); if (!NewElVal) { - dbg.Verbose(1, "gdcmHeader::ObtainElValueByName", - "failed to allocate gdcmElValue"); - return (gdcmElValue*)0; + dbg.Verbose(1, "gdcmHeader::ObtainHeaderEntryByName", + "failed to allocate gdcmHeaderEntry"); + return (gdcmHeaderEntry*)0; } return NewElVal; } @@ -2301,64 +2334,48 @@ gdcmElValue* gdcmHeader::NewElValueByName(std::string Name) { * @param Group group of the underlying DictEntry * @param Elem element of the underlying DictEntry */ -gdcmElValue* gdcmHeader::NewElValueByNumber(guint16 Group, guint16 Elem) { +gdcmHeaderEntry* gdcmHeader::NewHeaderEntryByNumber(guint16 Group, guint16 Elem) { // Find out if the tag we encountered is in the dictionaries: gdcmDictEntry * NewTag = GetDictEntryByNumber(Group, Elem); if (!NewTag) NewTag = new gdcmDictEntry(Group, Elem); - gdcmElValue* NewElVal = new gdcmElValue(NewTag); + gdcmHeaderEntry* NewElVal = new gdcmHeaderEntry(NewTag); if (!NewElVal) { - dbg.Verbose(1, "gdcmHeader::NewElValueByNumber", - "failed to allocate gdcmElValue"); - return (gdcmElValue*)0; + dbg.Verbose(1, "gdcmHeader::NewHeaderEntryByNumber", + "failed to allocate gdcmHeaderEntry"); + return (gdcmHeaderEntry*)0; } return NewElVal; } -/** - * \ingroup gdcmHeader - * \brief Searches within the public dictionary for a Dicom Element of - * a given tag. - * @param tagName name of the searched Dicom Element. - * @return Corresponding Dicom Element when it exists, and NULL - * otherwise. - */ - gdcmElValue* gdcmHeader::GetElementByName(std::string tagName) { - gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); - if( dictEntry == NULL) - return (gdcmElValue*)NULL; - return(PubElValSet.GetElementByNumber(dictEntry->GetGroup(), - dictEntry->GetElement())); -} - /** * \ingroup gdcmHeader * \brief Small utility function that creates a new manually crafted - * (as opposed as read from the file) gdcmElValue with user + * (as opposed as read from the file) gdcmHeaderEntry with user * specified name and adds it to the public tag hash table. * \note A fake TagKey is generated so the PubDict can keep it's coherence. * @param NewTagName The name to be given to this new tag. * @param VR The Value Representation to be given to this new tag. * @ return The newly hand crafted Element Value. */ -gdcmElValue* gdcmHeader::NewManualElValToPubDict(std::string NewTagName, - std::string VR) { - gdcmElValue* NewElVal = (gdcmElValue*)0; +gdcmHeaderEntry* gdcmHeader::NewManualHeaderEntryToPubDict(std::string NewTagName, + std::string VR) { + gdcmHeaderEntry* NewElVal = (gdcmHeaderEntry*)0; guint32 StuffGroup = 0xffff; // Group to be stuffed with additional info guint32 FreeElem = 0; gdcmDictEntry* NewEntry = (gdcmDictEntry*)0; - FreeElem = PubElValSet.GenerateFreeTagKeyInGroup(StuffGroup); + FreeElem = PubEntrySet.GenerateFreeTagKeyInGroup(StuffGroup); if (FreeElem == UINT32_MAX) { dbg.Verbose(1, "gdcmHeader::NewManualElValToPubDict", "Group 0xffff in Public Dict is full"); - return (gdcmElValue*)0; + return (gdcmHeaderEntry*)0; } NewEntry = new gdcmDictEntry(StuffGroup, FreeElem, VR, "GDCM", NewTagName); - NewElVal = new gdcmElValue(NewEntry); - PubElValSet.Add(NewElVal); + NewElVal = new gdcmHeaderEntry(NewEntry); + PubEntrySet.Add(NewElVal); return NewElVal; }