#include <stdio.h>
#include <cerrno>
-/*// For nthos:
-#ifdef _MSC_VER
- #include <winsock.h>
-#else
- #include <netinet/in.h>
-#endif*/
#include <cctype> // for isalpha
-/*#ifdef GDCM_NO_ANSI_STRING_STREAM
-# include <strstream>
-# define ostringstream ostrstream
-# else
-# include <sstream>
-#endif*/
-
#include "gdcmUtil.h"
#include "gdcmTS.h"
-//-----------------------------------------------------------------------------
-// Refer to gdcmHeader::CheckSwap()
-//const unsigned int gdcmHeader::HEADER_LENGTH_TO_READ = 256;
-
-// Refer to gdcmHeader::SetMaxSizeLoadEntry()
-//const unsigned int gdcmHeader::MAX_SIZE_LOAD_ELEMENT_VALUE = 4096;
//-----------------------------------------------------------------------------
// Constructor / Destructor
* @param enable_sequences = true to allow the header
* to be parsed *inside* the SeQuences,
* when they have an actual length
+ * @param ignore_shadow = true if user wants to skip shadow groups
+ during parsing, to save memory space
*\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,
- bool enable_sequences ):
- gdcmParser(InFilename,exception_on_error,enable_sequences)
-{
+ bool enable_sequences,
+ bool ignore_shadow):
+ gdcmParser(InFilename,exception_on_error,enable_sequences,ignore_shadow)
+{
+
+ // for some ACR-NEMA images GrPixel, NumPixel is *not* 7fe0,0010
+ // We may encounter the 'RETired' (0x0028, 0x0200) tag
+ // (Image Location") . This Element contains the number of
+ // 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
+ // is conventionally the element 0x0010 (when the norm is respected).
+ // When the "Image Location" is absent we default to group 0x7fe0.
+
+ // This IS the right place for the code
+
+ std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
+ if ( ImageLocation == GDCM_UNFOUND ) { // Image Location
+ GrPixel = 0x7fe0; // default value
+ } else {
+ GrPixel = (guint16) atoi( ImageLocation.c_str() );
+ }
+ if (GrPixel == 0xe07f) // sometimes Image Location value doesn't follow
+ GrPixel = 0x7fe0; // the supposed processor endianity.
+ // see gdcmData/cr172241.dcm
+ if (GrPixel != 0x7fe0)
+ // This is a kludge for old dirty Philips imager.
+ NumPixel = 0x1010;
+ else
+ NumPixel = 0x0010;
+
+ TagKey key = gdcmDictEntry::TranslateToKey(GrPixel, NumPixel);
+ countGrPixel = GetEntry().count(key);
}
/**
//-----------------------------------------------------------------------------
// Print
+// see gdcmParser.cxx
//-----------------------------------------------------------------------------
// Public
+/**
+ * \ingroup gdcmHeader
+ * \brief This predicate, based on hopefully reasonable heuristics,
+ * decides whether or not the current gdcmParser was properly parsed
+ * and contains the mandatory information for being considered as
+ * a well formed and usable Dicom/Acr File.
+ * @return true when gdcmParser is the one of a reasonable Dicom/Acr file,
+ * false otherwise.
+ */
+bool gdcmHeader::IsReadable(void) {
+ if(!gdcmParser::IsReadable()) {
+ return(false);
+ }
+ std::string res = GetEntryByNumber(0x0028, 0x0005);
+ if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 )
+ return false; // Image Dimensions
+ if ( !GetHeaderEntryByNumber(0x0028, 0x0100) )
+ return false; // "Bits Allocated"
+ if ( !GetHeaderEntryByNumber(0x0028, 0x0101) )
+ return false; // "Bits Stored"
+ if ( !GetHeaderEntryByNumber(0x0028, 0x0102) )
+ return false; // "High Bit"
+ if ( !GetHeaderEntryByNumber(0x0028, 0x0103) )
+ return false; // "Pixel Representation"
+ return true;
+}
+
/**
* \ingroup gdcmHeader
* \brief Determines if the Transfer Syntax was already encountered
if ( !Element )
return false;
LoadHeaderEntrySafe(Element);
-
- std::string Transfer = Element->GetValue();
- if ( Transfer == "1.2.840.10008.1.2.4.51" )
- return true;
- return false;
+ return ( Element->GetValue() == "1.2.840.10008.1.2.4.51" );
}
/**
LoadHeaderEntrySafe(Element);
std::string Transfer = Element->GetValue();
- if ( Transfer == "1.2.840.10008.1.2.5" )
+ if ( Transfer == "1.2.840.10008.1.2.5" ) {
return true;
+ }
return false;
}
* 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 = GetEntryByNumber(0x0028,0x0011);
+ std::string StrSize;
+ StrSize = GetEntryByNumber(0x0028,0x0011);
if (StrSize == GDCM_UNFOUND)
return 0;
return atoi(StrSize.c_str());
* (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 = GetEntryByNumber(0x0028,0x0010);
if (StrSize != GDCM_UNFOUND)
return atoi(StrSize.c_str());
* @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) {
+int gdcmHeader::GetBitsStored(void) {
std::string StrSize = GetEntryByNumber(0x0028,0x0101);
if (StrSize == GDCM_UNFOUND)
return 0; // It's supposed to be mandatory
* @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) {
+int gdcmHeader::GetBitsAllocated(void) { // TODO : move to gdcmFile
std::string StrSize = GetEntryByNumber(0x0028,0x0100);
if (StrSize == GDCM_UNFOUND)
return 0; // It's supposed to be mandatory
* @return The encountered number of Samples Per Pixel, 1 by default.
* (Gray level Pixels)
*/
-int gdcmHeader::GetSamplesPerPixel(void) {
+int gdcmHeader::GetSamplesPerPixel(void) { // TODO : move to gdcmFile
std::string StrSize = GetEntryByNumber(0x0028,0x0002);
if (StrSize == GDCM_UNFOUND)
return 1; // Well, it's supposed to be mandatory ...
*
* @return The encountered Planar Configuration, 0 by default.
*/
-int gdcmHeader::GetPlanarConfiguration(void) {
+int gdcmHeader::GetPlanarConfiguration(void) {
std::string StrSize = GetEntryByNumber(0x0028,0x0006);
if (StrSize == GDCM_UNFOUND)
return 0;
* \ 24 bit images appear as 8 bit
* @return 0S if nothing found. NOT USABLE file. The caller has to check
*/
-std::string gdcmHeader::GetPixelType(void) {
+std::string gdcmHeader::GetPixelType(void) {
std::string BitsAlloc = GetEntryByNumber(0x0028, 0x0100); // Bits Allocated
if (BitsAlloc == GDCM_UNFOUND) {
dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated");
return( BitsAlloc + Signed);
}
+
/**
* \ingroup gdcmHeader
- * \brief Recover the offset (from the beginning of the file) of the pixels.
+ * \brief Recover the offset (from the beginning of the file)
+ * \ of *image* pixels (not *icone image* pixels, if any !)
*/
-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
- // 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
- // is conventionally the element 0x0010 (when the norm is respected).
- // When the "Image Location" is absent we default to group 0x7fe0.
- guint16 grPixel;
- guint16 numPixel;
- std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
-
- if ( ImageLocation == GDCM_UNFOUND ) { // Image Location
- grPixel = 0x7fe0;
- } else {
- grPixel = (guint16) atoi( ImageLocation.c_str() );
- }
- if (grPixel != 0x7fe0)
- // This is a kludge for old dirty Philips imager.
- numPixel = 0x1010;
- else
- numPixel = 0x0010;
-
- gdcmHeaderEntry* PixelElement = GetHeaderEntryByNumber(grPixel,numPixel);
- if (PixelElement)
+size_t gdcmHeader::GetPixelOffset(void) {
+ //
+ // If the element (0x0088,0x0200) 'icone image sequence' is found
+ // (grPixel,numPixel) is stored twice : the first one for the icon
+ // the second one for the image ...
+ // pb : sometimes , (0x0088,0x0200) exists, but doesn't contain *anything*
+ // see gdcmData/MxTwinLossLess.dcm ...
+
+ //std::string icone = GetEntryByNumber(0x0088,0x0200); //icone image sequence
+
+ IterHT it = GetHeaderEntrySameNumber(GrPixel,NumPixel);
+ TagKey key = gdcmDictEntry::TranslateToKey(GrPixel,NumPixel);
+ gdcmHeaderEntry* PixelElement;
+ if (countGrPixel == 1)
+ PixelElement = (it.first)->second;
+ else {
+ PixelElement = (++it.first)->second; // hope there are no more than 2 !
+ }
+ if (PixelElement) {
return PixelElement->GetOffset();
- else
+ } else {
return 0;
+ std::cout << "Big trouble : Pixel Element ("
+ << std::hex << GrPixel<<","<< NumPixel<< ") NOT found"
+ << std::endl;
+ }
}
-
+// TODO : unify those two (previous one and next one)
/**
* \ingroup gdcmHeader
* \brief Recover the pixel area length (in Bytes)
- * @return 0 by default. NOT USABLE file. The caller has to check.
+ * @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 gdcmHeader::GetPixelAreaLength(void) {
- // If this file complies with the norm we should encounter 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
- // is conventionally the element 0x0010 (when the norm is respected).
- // When the "Image Location" is absent we default to group 0x7fe0.
- guint16 grPixel;
- guint16 numPixel;
- std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
- if ( ImageLocation == GDCM_UNFOUND ) {
- grPixel = 0x7fe0;
- } else {
- grPixel = (guint16) atoi( ImageLocation.c_str() );
- }
- if (grPixel != 0x7fe0)
- // This is a kludge for old dirty Philips imager.
- numPixel = 0x1010;
+size_t gdcmHeader::GetPixelAreaLength(void) {
+
+ IterHT it = GetHeaderEntrySameNumber(GrPixel,NumPixel);
+ TagKey key = gdcmDictEntry::TranslateToKey(GrPixel,NumPixel);
+ gdcmHeaderEntry* PixelElement;
+
+ if (countGrPixel==1)
+ PixelElement = (it.first)->second;
else
- numPixel = 0x0010;
-
- gdcmHeaderEntry* PixelElement = GetHeaderEntryByNumber(grPixel,numPixel);
- if (PixelElement)
+ PixelElement = (++it.first)->second;
+
+ if (PixelElement) {
return PixelElement->GetLength();
- else
+ } else {
+ std::cout << "Big trouble : Pixel Element ("
+ << std::hex << GrPixel<<","<< NumPixel<< ") NOT found"
+ << std::endl;
return 0;
+ }
}
/**
bool gdcmHeader::HasLUT(void) {
// Check the presence of the LUT Descriptors
+
+ // LutDescriptorRed
if ( !GetHeaderEntryByNumber(0x0028,0x1101) )
return false;
// LutDescriptorGreen
// LutDescriptorBlue
if ( !GetHeaderEntryByNumber(0x0028,0x1103) )
return false;
- // It is not enough
- // we check also
+
+ // It is not enough :
+ // we check also
+
+ // Red Palette Color Lookup Table Data
if ( !GetHeaderEntryByNumber(0x0028,0x1201) )
- return false;
+ return false;
+ // Green Palette Color Lookup Table Data
if ( !GetHeaderEntryByNumber(0x0028,0x1202) )
return false;
+ // Blue Palette Color Lookup Table Data
if ( !GetHeaderEntryByNumber(0x0028,0x1203) )
return false;
return true;
tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
Tokenize (LutDescriptionG, tokens, "\\");
lengthG=atoi(tokens[0].c_str()); // Green LUT length in Bytes
- debG =atoi(tokens[1].c_str());
- nbitsG =atoi(tokens[2].c_str());
+ debG =atoi(tokens[1].c_str()); // subscript of the first Lut Value
+ nbitsG =atoi(tokens[2].c_str()); // Lut item size (in Bits)
tokens.clear();
tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
Tokenize (LutDescriptionB, tokens, "\\");
lengthB=atoi(tokens[0].c_str()); // Blue LUT length in Bytes
- debB =atoi(tokens[1].c_str());
- nbitsB =atoi(tokens[2].c_str());
+ debB =atoi(tokens[1].c_str()); // subscript of the first Lut Value
+ nbitsB =atoi(tokens[2].c_str()); // Lut item size (in Bits)
tokens.clear();
// Load LUTs into memory, (as they were stored on disk)
// if it works, we shall have to check the 3 Palettes
// to see which byte is ==0 (first one, or second one)
// and fix the code
- // We give up the checking to avoid some overhead
+ // We give up the checking to avoid some (useless ?)overhead
+ // (optimistic asumption)
unsigned char *a;
int i;
}
//How to free the now useless LUTs?
-
//free(LutR); free(LutB); free(LutG); // Seg Fault when used
return(LUTRGBA);
}
*/
void gdcmHeader::SetImageDataSize(size_t ImageDataSize) {
std::string content1;
- char car[20];
- // Assumes HeaderEntry (0x7fe0, 0x0010) exists ...
+ char car[20];
+
+ // Assumes HeaderEntry (GrPixel, NumPixel) is unique ...
+ // TODO deal with multiplicity (see gdcmData/icone.dcm)
sprintf(car,"%d",ImageDataSize);
- gdcmHeaderEntry *a = GetHeaderEntryByNumber(0x7fe0, 0x0010);
+ gdcmHeaderEntry *a = GetHeaderEntryByNumber(GrPixel, NumPixel);
a->SetLength(ImageDataSize);
ImageDataSize+=8;
sprintf(car,"%d",ImageDataSize);
content1=car;
- SetEntryByNumber(content1, 0x7fe0, 0x0000);
+ SetEntryByNumber(content1, GrPixel, NumPixel);
+}
+
+bool gdcmHeader::operator<(gdcmHeader &header)
+{
+ std::string s1,s2;
+
+ // Patient Name
+ s1=this->GetEntryByNumber(0x0010,0x0010);
+ s2=header.GetEntryByNumber(0x0010,0x0010);
+ if(s1 < s2)
+ return(true);
+ else if(s1 > s2)
+ return(false);
+ else
+ {
+ // Patient ID
+ s1=this->GetEntryByNumber(0x0010,0x0020);
+ s2=header.GetEntryByNumber(0x0010,0x0020);
+ if (s1 < s2)
+ return(true);
+ else if (s1 > s2)
+ return(1);
+ else
+ {
+ // Study Instance UID
+ s1=this->GetEntryByNumber(0x0020,0x000d);
+ s2=header.GetEntryByNumber(0x0020,0x000d);
+ if (s1 < s2)
+ return(true);
+ else if(s1 > s2)
+ return(false);
+ else
+ {
+ // Serie Instance UID
+ s1=this->GetEntryByNumber(0x0020,0x000e);
+ s2=header.GetEntryByNumber(0x0020,0x000e);
+ if (s1 < s2)
+ return(true);
+ else if(s1 > s2)
+ return(false);
+ }
+ }
+ }
+ return(false);
}
//-----------------------------------------------------------------------------