-void gdcmHeader::CheckSwap()
-{
- guint32 s;
- guint32 x=4; // x : pour ntohs
- bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
-
- int lgrLue;
- char * entCur;
- char deb[HEADER_LENGHT_TO_READ];
-
- // First, compare HostByteOrder and NetworkByteOrder in order to
- // determine if we shall need to swap bytes (i.e. the Endian type).
- if (x==ntohs(x))
- net2host = true;
- else
- 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);
-
- entCur = deb + 128;
- if(memcmp(entCur, "DICM", (size_t)4) == 0) {
- filetype = TrueDicom;
- dbg.Verbose(0, "gdcmHeader::CheckSwap:", "looks like DICOM Version3");
- } else {
- filetype = Unknown;
- dbg.Verbose(0, "gdcmHeader::CheckSwap:", "not a DICOM Version3 file");
- }
-
- if(filetype == TrueDicom) {
- // Next, determine the value representation (VR). Let's skip to the
- // first element (0002, 0000) and check there if we find "UL", in
- // which case we (almost) know it is explicit VR.
- // WARNING: if it happens to be implicit VR then what we will read
- // is the length of the group. If this ascii representation of this
- // length happens to be "UL" then we shall believe it is explicit VR.
- // FIXME: in order to fix the above warning, we could read the next
- // element value (or a couple of elements values) in order to make
- // sure we are not commiting a big mistake.
- // We need to skip :
- // * the 128 bytes of File Preamble (often padded with zeroes),
- // * the 4 bytes of "DICM" string,
- // * the 4 bytes of the first tag (0002, 0000),
- // i.e. a total of 136 bytes.
- entCur = deb + 136;
- if(memcmp(entCur, "UL", (size_t)2) == 0) {
- filetype = ExplicitVR;
- dbg.Verbose(0, "gdcmHeader::CheckSwap:",
- "explicit Value Representation");
- } else {
- filetype = ImplicitVR;
- dbg.Verbose(0, "gdcmHeader::CheckSwap:",
- "not an explicit Value Representation");
- }
-
- if (net2host) {
- sw = 4321;
- dbg.Verbose(0, "gdcmHeader::CheckSwap:",
- "HostByteOrder != NetworkByteOrder");
- } else {
- sw = 0;
- dbg.Verbose(0, "gdcmHeader::CheckSwap:",
- "HostByteOrder = NetworkByteOrder");
- }
-
- // Position the file position indicator at first tag (i.e.
- // after the file preamble and the "DICM" string).
- rewind(fp);
- fseek (fp, 132L, SEEK_SET);
- return;
- } // End of TrueDicom
-
- // Alas, this is not a DicomV3 file and whatever happens there is no file
- // preamble. We can reset the file position indicator to where the data
- // is (i.e. the beginning of the file).
- rewind(fp);
-
- // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
- // By clean we mean that the length of the first tag is written down.
- // If this is the case and since the length of the first group HAS to be
- // four (bytes), then determining the proper swap code is straightforward.
-
- entCur = deb + 4;
- s = str2num(entCur, int);
-
- switch (s) {
- case 0x00040000 :
- sw=3412;
- filetype = ACR;
- return;
- case 0x04000000 :
- sw=4321;
- filetype = ACR;
- return;
- case 0x00000400 :
- sw=2143;
- filetype = ACR;
- return;
- case 0x00000004 :
- sw=0;
- filetype = ACR;
- return;
- default :
- dbg.Verbose(0, "gdcmHeader::CheckSwap:",
- "ACE/NEMA unfound swap info (time to raise bets)");
- }
-
- // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
- // It is time for despaired wild guesses. So, let's assume this file
- // happens to be 'dirty' ACR/NEMA, i.e. the length of the group it
- // not present. Then the only info we have is the net2host one.
- //FIXME Si c'est du RAW, ca degagera + tard
-
- if (! net2host )
- sw = 0;
- else
- sw = 4321;
- return;
-}
-
-/**
- * \ingroup gdcmHeader
- * \brief recupere la longueur d'un champ DICOM.
- * Preconditions:
- * 1/ le fichier doit deja avoir ete ouvert,
- * 2/ CheckSwap() doit avoir ete appele
- * 3/ la partie 'group' ainsi que la partie 'elem'
- * de l'acr_element doivent avoir ete lues.
- *
- * ACR-NEMA : we allways get
- * GroupNumber (2 Octets)
- * ElementNumber (2 Octets)
- * ElementSize (4 Octets)
- * DICOM en implicit Value Representation :
- * GroupNumber (2 Octets)
- * ElementNumber (2 Octets)
- * ElementSize (4 Octets)
- *
- * DICOM en explicit Value Representation :
- * GroupNumber (2 Octets)
- * ElementNumber (2 Octets)
- * ValueRepresentation (2 Octets)
- * ElementSize (2 Octets)
- *
- * ATTENTION : dans le cas ou ValueRepresentation = OB, OW, SQ, UN
- * GroupNumber (2 Octets)
- * ElementNumber (2 Octets)
- * ValueRepresentation (2 Octets)
- * zone reservee (2 Octets)
- * ElementSize (4 Octets)
- *
- * @param sw code swap
- * @param skippedLength pointeur sur nombre d'octets que l'on a saute qd
- * la lecture est finie
- * @param longueurLue pointeur sur longueur (en nombre d'octets)
- * effectivement lue
- * @return longueur retenue pour le champ
+float gdcmHeader::GetRescaleSlope()
+{
+ float resSlope = 1.;
+ std::string strRescSlope = GetEntryByNumber(0x0028,0x1053); //0028 1053 DS IMG Rescale Slope
+ if ( strRescSlope != GDCM_UNFOUND )
+ {
+ if( sscanf( strRescSlope.c_str(), "%f", &resSlope) != 1)
+ {
+ // bug in the element 0x0028,0x1053
+ dbg.Verbose(0, "gdcmHeader::GetRescaleSlope: Rescale Slope is empty");
+ }
+ }
+
+ return resSlope;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief This function is intended to user who doesn't want
+ * to have to manage a LUT and expects to get an RBG Pixel image
+ * (or a monochrome one ...)
+ * \warning to be used with GetImagePixels()
+ * @return 1 if Gray level, 3 if Color (RGB, YBR or PALETTE COLOR)
+ */
+int gdcmHeader::GetNumberOfScalarComponents()
+{
+ if ( GetSamplesPerPixel() == 3 )
+ {
+ return 3;
+ }
+
+ // 0028 0100 US IMG Bits Allocated
+ // (in order no to be messed up by old RGB images)
+ if ( GetEntryByNumber(0x0028,0x0100) == "24" )
+ {
+ return 3;
+ }
+
+ std::string strPhotometricInterpretation = GetEntryByNumber(0x0028,0x0004);
+
+ if ( ( strPhotometricInterpretation == "PALETTE COLOR ") )
+ {
+ if ( HasLUT() )// PALETTE COLOR is NOT enough
+ {
+ return 3;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ // beware of trailing space at end of string
+ // DICOM tags are never of odd length
+ if ( strPhotometricInterpretation == GDCM_UNFOUND ||
+ strPhotometricInterpretation == "MONOCHROME1 " ||
+ strPhotometricInterpretation == "MONOCHROME2 " )
+ {
+ return 1;
+ }
+ else
+ {
+ // we assume that *all* kinds of YBR are dealt with
+ return 3;
+ }
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief This function is intended to user that DOESN'T want
+ * to get RGB pixels image when it's stored as a PALETTE COLOR image
+ * - the (vtk) user is supposed to know how deal with LUTs -
+ * \warning to be used with GetImagePixelsRaw()
+ * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -)
+ */
+int gdcmHeader::GetNumberOfScalarComponentsRaw()
+{
+ // 0028 0100 US IMG Bits Allocated
+ // (in order no to be messed up by old RGB images)
+ if ( gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24" )
+ {
+ return 3;
+ }
+
+ // we assume that *all* kinds of YBR are dealt with
+ return GetSamplesPerPixel();
+}
+
+//
+// -------------- Remember ! ----------------------------------
+//
+// Image Position Patient (0020,0032):
+// If not found (ACR_NEMA) we try Image Position (0020,0030)
+// If not found (ACR-NEMA), we consider Slice Location (0020,1041)
+// or Location (0020,0050)
+// as the Z coordinate,
+// 0. for all the coordinates if nothing is found
+
+// \todo find a way to inform the caller nothing was found
+// \todo How to tell the caller a wrong number of values was found?
+//
+// ---------------------------------------------------------------
+//
+
+/**
+ * \brief gets the info from 0020,0032 : Image Position Patient
+ * else from 0020,0030 : Image Position (RET)
+ * else 0.
+ * @return up-left image corner X position
+ */
+
+float gdcmHeader::GetXOrigin()
+{
+ float xImPos, yImPos, zImPos;
+ std::string strImPos = GetEntryByNumber(0x0020,0x0032);
+
+ if ( strImPos == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position Patient (0020,0032)");
+ strImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
+ if ( strImPos == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position (RET) (0020,0030)");
+ /// \todo How to tell the caller nothing was found ?
+ return 0.;
+ }
+ }
+
+ if( sscanf( strImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3 )
+ {
+ return 0.;
+ }
+
+ return xImPos;
+}
+
+/**
+ * \brief gets the info from 0020,0032 : Image Position Patient
+ * else from 0020,0030 : Image Position (RET)
+ * else 0.
+ * @return up-left image corner Y position
+ */
+float gdcmHeader::GetYOrigin()
+{
+ float xImPos, yImPos, zImPos;
+ std::string strImPos = GetEntryByNumber(0x0020,0x0032);
+
+ if ( strImPos == GDCM_UNFOUND)
+ {
+ dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position Patient (0020,0032)");
+ strImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
+ if ( strImPos == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position (RET) (0020,0030)");
+ /// \todo How to tell the caller nothing was found ?
+ return 0.;
+ }
+ }
+
+ if( sscanf( strImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3 )
+ {
+ return 0.;
+ }
+
+ return yImPos;
+}
+
+/**
+ * \brief gets the info from 0020,0032 : Image Position Patient
+ * \ else from 0020,0030 : Image Position (RET)
+ * \ else from 0020,1041 : Slice Location
+ * \ else from 0020,0050 : Location
+ * \ else 0.
+ * @return up-left image corner Z position
+ */
+float gdcmHeader::GetZOrigin()
+{
+ float xImPos, yImPos, zImPos;
+ std::string strImPos = GetEntryByNumber(0x0020,0x0032);
+
+ if ( strImPos != GDCM_UNFOUND )
+ {
+ if( sscanf( strImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3)
+ {
+ dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position Patient (0020,0032)");
+ return 0.; // bug in the element 0x0020,0x0032
+ }
+ else
+ {
+ return zImPos;
+ }
+ }
+
+ strImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
+ if ( strImPos != GDCM_UNFOUND )
+ {
+ if( sscanf( strImPos.c_str(),
+ "%f\\%f\\%f", &xImPos, &yImPos, &zImPos ) != 3 )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position (RET) (0020,0030)");
+ return 0.; // bug in the element 0x0020,0x0032
+ }
+ else
+ {
+ return zImPos;
+ }
+ }
+
+ std::string strSliceLocation = GetEntryByNumber(0x0020,0x1041); // for *very* old ACR-NEMA images
+ if ( strSliceLocation != GDCM_UNFOUND )
+ {
+ if( sscanf( strSliceLocation.c_str(), "%f", &zImPos) != 1)
+ {
+ dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Slice Location (0020,1041)");
+ return 0.; // bug in the element 0x0020,0x1041
+ }
+ else
+ {
+ return zImPos;
+ }
+ }
+ dbg.Verbose(0, "gdcmHeader::GetZImagePosition: unfound Slice Location (0020,1041)");
+
+ std::string strLocation = GetEntryByNumber(0x0020,0x0050);
+ if ( strLocation != GDCM_UNFOUND )
+ {
+ if( sscanf( strLocation.c_str(), "%f", &zImPos) != 1)
+ {
+ dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Location (0020,0050)");
+ return 0.; // bug in the element 0x0020,0x0050
+ }
+ else
+ {
+ return zImPos;
+ }
+ }
+ dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Location (0020,0050)");
+
+ return 0.; // Hopeless
+}
+
+/**
+ * \brief gets the info from 0020,0013 : Image Number
+ * \ else 0.
+ * @return image number
+ */
+int gdcmHeader::GetImageNumber()
+{
+ // The function i atoi() takes the address of an area of memory as
+ // parameter and converts the string stored at that location to an integer
+ // using the external decimal to internal binary conversion rules. This may
+ // be preferable to sscanf() since atoi() is a much smaller, simpler and
+ // faster function. sscanf() can do all possible conversions whereas
+ // atoi() can only do single decimal integer conversions.
+ std::string strImNumber = GetEntryByNumber(0x0020,0x0013); //0020 0013 IS REL Image Number
+ if ( strImNumber != GDCM_UNFOUND )
+ {
+ return atoi( strImNumber.c_str() );
+ }
+ return 0; //Hopeless
+}
+
+/**
+ * \brief gets the info from 0008,0060 : Modality
+ * @return Modality Type
+ */
+ModalityType gdcmHeader::GetModality()
+{
+ // 0008 0060 CS ID Modality
+ std::string strModality = GetEntryByNumber(0x0008,0x0060);
+ if ( strModality != GDCM_UNFOUND )
+ {
+ if ( strModality.find("AU") < strModality.length()) return AU;
+ else if ( strModality.find("AS") < strModality.length()) return AS;
+ else if ( strModality.find("BI") < strModality.length()) return BI;
+ else if ( strModality.find("CF") < strModality.length()) return CF;
+ else if ( strModality.find("CP") < strModality.length()) return CP;
+ else if ( strModality.find("CR") < strModality.length()) return CR;
+ else if ( strModality.find("CT") < strModality.length()) return CT;
+ else if ( strModality.find("CS") < strModality.length()) return CS;
+ else if ( strModality.find("DD") < strModality.length()) return DD;
+ else if ( strModality.find("DF") < strModality.length()) return DF;
+ else if ( strModality.find("DG") < strModality.length()) return DG;
+ else if ( strModality.find("DM") < strModality.length()) return DM;
+ else if ( strModality.find("DS") < strModality.length()) return DS;
+ else if ( strModality.find("DX") < strModality.length()) return DX;
+ else if ( strModality.find("ECG") < strModality.length()) return ECG;
+ else if ( strModality.find("EPS") < strModality.length()) return EPS;
+ else if ( strModality.find("FA") < strModality.length()) return FA;
+ else if ( strModality.find("FS") < strModality.length()) return FS;
+ else if ( strModality.find("HC") < strModality.length()) return HC;
+ else if ( strModality.find("HD") < strModality.length()) return HD;
+ else if ( strModality.find("LP") < strModality.length()) return LP;
+ else if ( strModality.find("LS") < strModality.length()) return LS;
+ else if ( strModality.find("MA") < strModality.length()) return MA;
+ else if ( strModality.find("MR") < strModality.length()) return MR;
+ else if ( strModality.find("NM") < strModality.length()) return NM;
+ else if ( strModality.find("OT") < strModality.length()) return OT;
+ else if ( strModality.find("PT") < strModality.length()) return PT;
+ else if ( strModality.find("RF") < strModality.length()) return RF;
+ else if ( strModality.find("RG") < strModality.length()) return RG;
+ else if ( strModality.find("RTDOSE") < strModality.length()) return RTDOSE;
+ else if ( strModality.find("RTIMAGE") < strModality.length()) return RTIMAGE;
+ else if ( strModality.find("RTPLAN") < strModality.length()) return RTPLAN;
+ else if ( strModality.find("RTSTRUCT") < strModality.length()) return RTSTRUCT;
+ else if ( strModality.find("SM") < strModality.length()) return SM;
+ else if ( strModality.find("ST") < strModality.length()) return ST;
+ else if ( strModality.find("TG") < strModality.length()) return TG;
+ else if ( strModality.find("US") < strModality.length()) return US;
+ else if ( strModality.find("VF") < strModality.length()) return VF;
+ else if ( strModality.find("XA") < strModality.length()) return XA;
+ else if ( strModality.find("XC") < strModality.length()) return XC;
+
+ else
+ {
+ /// \todo throw error return value ???
+ /// specified <> unknow in our database
+ return Unknow;
+ }
+ }
+
+ return Unknow;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \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 !