+
+/**
+ * \ingroup gdcmHeader
+ * \brief
+ * @return
+ */
+int gdcmHeader::Write(FILE * fp, FileType type) {
+ return PubElValSet.Write(fp, type);
+}
+
+//
+// ------------------------ 'non string' elements related functions
+//
+
+/**
+ * \ingroup gdcmHeader
+ * \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);
+ if ( !Element )
+ return NULL;
+ size_t o =(size_t)Element->GetOffset();
+ fseek(fp, o, SEEK_SET);
+ int l=Element->GetLength();
+ void * a = malloc(l);
+ if(!a) {
+ cout << "Big Broblem (LoadElementVoidArea, malloc) "
+ << std::hex << Group << " " << Elem << std::endl;
+ return NULL;
+ }
+ int res = PubElValSet.SetVoidAreaByNumber(a, Group, Elem);
+ // TODO check the result
+ size_t l2 = fread(a, 1, l ,fp);
+ if(l != l2) {
+ cout << "Big Broblem (LoadElementVoidArea, fread) "
+ << std::hex << Group << " " << Elem << std::endl;
+ free(a);
+ return NULL;
+ }
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Gets (from Header) the offset of a 'non string' element value
+ * \ (LoadElementValue 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");
+ return (size_t)0;
+ }
+ return elValue->GetOffset();
+}
+
+/**
+ * \ingroup gdcmHeader
+* \brief Gets (from Header) a 'non string' element value
+ * \ (LoadElementValue 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");
+ return (NULL);
+ }
+ return elValue->GetVoidArea();
+}
+
+
+//
+// =============================================================================
+// Heuristics based accessors
+//==============================================================================
+//
+
+// TODO : move to an other file.
+
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Retrieve the number of columns of image.
+ * @return The encountered size when found, 0 by default.
+ */
+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);
+ if (StrSize == GDCM_UNFOUND)
+ return 0;
+ return atoi(StrSize.c_str());
+}
+
+/**
+ * \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.
+ */
+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);
+ 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
+ // hence be a signal (1d image). So we default to 1:
+ return 1;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Retrieve the number of planes of volume or the number
+ * of frames of a multiframe.
+ * \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.
+ */
+int gdcmHeader::GetZSize(void) {
+ // Both in DicomV3 and ACR/Nema the consider the "Number of Frames"
+ // as the third dimension.
+ std::string StrSize = GetPubElValByNumber(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);
+ if (StrSize != GDCM_UNFOUND)
+ return atoi(StrSize.c_str());
+ return 1;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Retrieve the number of Bits Stored
+ * (as opposite to number of Bits Allocated)
+ *
+ * @return The encountered number of Bits Stored, 0 by default.
+ */
+int gdcmHeader::GetBitsStored(void) {
+ std::string StrSize = GetPubElValByNumber(0x0028,0x0101);
+ if (StrSize == GDCM_UNFOUND)
+ return 1;
+ return atoi(StrSize.c_str());
+}
+
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Retrieve the number of Samples Per Pixel
+ * (1 : gray level, 3 : RGB)
+ *
+ * @return The encountered number of Samples Per Pixel, 1 by default.
+ */
+int gdcmHeader::GetSamplesPerPixel(void) {
+ std::string StrSize = GetPubElValByNumber(0x0028,0x0002);
+ if (StrSize == GDCM_UNFOUND)
+ return 1; // Well, it's supposed to be mandatory ...
+ return atoi(StrSize.c_str());
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Retrieve the Planar Configuration for RGB images
+ * (0 : RGB Pixels , 1 : R Plane + G Plane + B Plane)
+ *
+ * @return The encountered Planar Configuration, 0 by default.
+ */
+int gdcmHeader::GetPlanarConfiguration(void) {
+ std::string StrSize = GetPubElValByNumber(0x0028,0x0006);
+ if (StrSize == GDCM_UNFOUND)
+ return 0;
+ return atoi(StrSize.c_str());
+}
+
+/**
+ * \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.
+ *
+ */
+int gdcmHeader::GetPixelSize(void) {
+ std::string PixelType = GetPixelType();
+ if (PixelType == "8U" || PixelType == "8S")
+ return 1;
+ if (PixelType == "16U" || PixelType == "16S")
+ return 2;
+ if (PixelType == "32U" || PixelType == "32S")
+ return 4;
+ dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type");
+ return 0;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Build the Pixel Type of the image.
+ * Possible values are:
+ * - 8U unsigned 8 bit,
+ * - 8S signed 8 bit,
+ * - 16U unsigned 16 bit,
+ * - 16S signed 16 bit,
+ * - 32U unsigned 32 bit,
+ * - 32S signed 32 bit,
+ * \warning 12 bit images appear as 16 bit.
+ * @return
+ */
+std::string gdcmHeader::GetPixelType(void) {
+ std::string BitsAlloc;
+ BitsAlloc = GetElValByName("Bits Allocated");
+ if (BitsAlloc == GDCM_UNFOUND) {
+ dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated");
+ BitsAlloc = std::string("16");
+ }
+ if (BitsAlloc == "12")
+ BitsAlloc = std::string("16");
+
+ std::string Signed;
+ Signed = GetElValByName("Pixel Representation");
+ if (Signed == GDCM_UNFOUND) {
+ dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation");
+ BitsAlloc = std::string("0");
+ }
+ if (Signed == "0")
+ Signed = std::string("U");
+ else
+ Signed = std::string("S");
+
+ return( BitsAlloc + Signed);
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief gets the info from 0002,0010 : Transfert Syntax
+ * \ else 1.
+ * @return Transfert Syntax Name (as oposite to Transfert Syntax UID)
+ */
+std::string gdcmHeader::GetTransferSyntaxName(void) {
+ std::string TransfertSyntax = GetPubElValByNumber(0x0002,0x0010);
+ if (TransfertSyntax == GDCM_UNFOUND) {
+ dbg.Verbose(0, "gdcmHeader::GetTransferSyntaxName: unfound Transfert Syntax (0002,0010)");
+ return "Uncompressed ACR-NEMA";
+ }
+ // we do it only when we need it
+ gdcmTS * ts = gdcmGlobal::GetTS();
+ std::string tsName=ts->GetValue(TransfertSyntax);
+ //delete ts; // Seg Fault when deleted ?!
+ return tsName;
+}
+
+// -------------------------------- Lookup Table related functions ------------
+
+/**
+ * \ingroup gdcmHeader
+ * \brief gets the info from 0028,1101 : Lookup Table Desc-Red
+ * \ else 0
+ * @return Lookup Table Length
+ * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
+ */
+
+int gdcmHeader::GetLUTLength(void) {
+ std::vector<std::string> tokens;
+ int LutLength;
+ //int LutDepth;
+ //int LutNbits;
+ // Just hope Lookup Table Desc-Red = Lookup Table Desc-Red = Lookup Table Desc-Blue
+ std::string LutDescriptionR = GetPubElValByNumber(0x0028,0x1101);
+ if (LutDescriptionR == GDCM_UNFOUND)
+ return 0;
+ std::string LutDescriptionG = GetPubElValByNumber(0x0028,0x1102);
+ if (LutDescriptionG == GDCM_UNFOUND)
+ return 0;
+ std::string LutDescriptionB = GetPubElValByNumber(0x0028,0x1103);
+ if (LutDescriptionB == GDCM_UNFOUND)
+ return 0;
+ if( (LutDescriptionR != LutDescriptionG) || (LutDescriptionR != LutDescriptionB) ) {
+ dbg.Verbose(0, "gdcmHeader::GetLUTLength: The CLUT R,G,B are not equal");
+ return 0;
+ }
+ cout << "Lut Description " << LutDescriptionR <<std::endl;
+ tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
+ Tokenize (LutDescriptionR, tokens, "\\");
+ LutLength=atoi(tokens[0].c_str());
+ //LutDepth=atoi(tokens[1].c_str());
+ //LutNbits=atoi(tokens[2].c_str());
+ tokens.clear();
+ return LutLength;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief gets the info from 0028,1101 : Lookup Table Desc-Red
+ * \ else 0
+ * @return Lookup Table nBit
+ * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
+ */
+
+int gdcmHeader::GetLUTNbits(void) {
+ std::vector<std::string> tokens;
+ //int LutLength;
+ //int LutDepth;
+ 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);
+ if (LutDescription == GDCM_UNFOUND)
+ return 0;
+ tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
+ Tokenize (LutDescription, tokens, "\\");
+ //LutLength=atoi(tokens[0].c_str());
+ //LutDepth=atoi(tokens[1].c_str());
+ LutNbits=atoi(tokens[2].c_str());
+ tokens.clear();
+ return LutNbits;
+}
+
+
+/**
+ * \ingroup gdcmHeader
+ * \brief gets the info from 0028,1201 : Lookup Table Red
+ * \ else 0
+ * @return Lookup Table Red
+ * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
+ */
+void * gdcmHeader::GetLUTRed(void) {
+ return GetPubElValVoidAreaByNumber(0x0028,0x1201);
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief gets the info from 0028,1202 : Lookup Table Green
+ * \ else 0
+ * @return Lookup Table Red
+ * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
+ */
+ void * gdcmHeader::GetLUTGreen(void) {
+ return GetPubElValVoidAreaByNumber(0x0028,0x1202);
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief gets the info from 0028,1202 : Lookup Table Blue
+ * \ else 0
+ * @return Lookup Table Blue
+ * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
+ */
+void * gdcmHeader::GetLUTBlue(void) {
+ return GetPubElValVoidAreaByNumber(0x0028,0x1203);
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief
+ * @return Lookup Table RGB
+ * \ when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
+ * \ and (0028,1201),(0028,1202),(0028,1202) are found
+ * \warning : hazardous ! Use better GetPubElValVoidAreaByNumber
+ */
+void * gdcmHeader::GetLUTRGB(void) {
+// Not so easy : see
+// http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
+// and OT-PAL-8-face.dcm
+
+ if (GetPubElValByNumber(0x0028,0x0004) == GDCM_UNFOUND) {
+ dbg.Verbose(0, "gdcmHeader::GetLUTRGB: unfound Photometric Interpretation");
+ return NULL;
+ }
+ void * LutR,*LutG,*LutB;
+ int l;
+
+ // Maybe, some day we get an image
+ // that respects the definition ...
+ // Let's consider no ones does.
+
+ l= GetLUTLength();
+ if(l==0)
+ return (NULL);
+ int nBits=GetLUTNbits();
+ // a virer quand on aura trouve UNE image
+ // qui correspond VRAIMENT à la definition !
+ cout << "l " << l << " nBits " << nBits;
+
+ l= l/(nBits/8);
+
+ LutR =GetPubElValVoidAreaByNumber(0x0028,0x1201);
+ LutG =GetPubElValVoidAreaByNumber(0x0028,0x1202);
+ LutB =GetPubElValVoidAreaByNumber(0x0028,0x1203);
+
+ // Warning : Any value for nBits as to be considered as 8
+ // Any value for Length as to be considered as 256
+ // That's DICOM ...
+
+ // Just wait before removing the following code
+ /*
+ if (nBits == 16) {
+ guint16 * LUTRGB, *rgb;
+ LUTRGB = rgb = (guint16 *) malloc(3*l*sizeof( guint16));
+ guint16 * r = (guint16 *)LutR;
+ guint16 * g = (guint16 *)LutG;
+ guint16 * b = (guint16 *)LutB;
+ for(int i=0;i<l;i++) {
+ *rgb++ = *r++;
+ *rgb++ = *g++;
+ *rgb++ = *b++;
+ }
+ return(LUTRGB);
+ } else
+
+ */ { // we assume it's always 8 Bits
+ l=256; // we assume ...
+ unsigned char * LUTRGB, *rgb;
+ LUTRGB = rgb = (unsigned char *) malloc(3*l*sizeof( char));
+ unsigned char * r = (unsigned char *)LutR;
+ unsigned char * g = (unsigned char *)LutG;
+ unsigned char * b = (unsigned char *)LutB;
+ for(int i=0;i<l;i++) {
+ //cout << "lut16 " << i << " : " << *r << " " << *g << " " << *b << std::endl;
+ printf("lut 8 %d : %d %d %d \n",i,*r,*g,*b);
+ *rgb++ = *r++;
+ *rgb++ = *g++;
+ *rgb++ = *b++;
+ }
+ free(LutR); free(LutB); free(LutG);
+ return(LUTRGB);
+ }
+}
+