+ * \brief Canonical destructor.
+ */
+gdcmHeader::~gdcmHeader ()
+{
+}
+
+
+/**
+ * \brief Performs some consistency checking on various 'File related'
+ * (as opposed to 'DicomDir related') entries
+ * then writes in a file all the (Dicom Elements) included the Pixels
+ * @param fp file pointer on an already open file
+ * @param filetype Type of the File to be written
+ * (ACR-NEMA, ExplicitVR, ImplicitVR)
+ */
+void gdcmHeader::Write(FILE* fp,FileType filetype) {
+
+ // Bits Allocated
+ if ( GetEntryByNumber(0x0028,0x0100) == "12") {
+ SetEntryByNumber("16", 0x0028,0x0100);
+ }
+
+ // correct Pixel group Length if necessary
+
+ // TODO : create a gdcmHeader::Write method and move this part.
+ // (only gdcmHeader knows GrPixel, NumPixel)
+
+ int i_lgPix = GetEntryLengthByNumber(GrPixel, NumPixel);
+ if (i_lgPix != -2) { // no (GrPixel, NumPixel) element
+ char * dumm = new char[20];
+ sprintf(dumm ,"%d", i_lgPix+12);
+ std::string s_lgPix = dumm;
+ delete dumm;
+ ReplaceOrCreateByNumber(s_lgPix,GrPixel, 0x0000);
+ }
+
+ // Drop Palette Color, if necessary
+
+ if ( GetEntryByNumber(0x0028,0x0002).c_str()[0] == '3' ) {
+ // if SamplesPerPixel = 3, sure we don't need any LUT !
+ // Drop 0028|1101, 0028|1102, 0028|1103
+ // Drop 0028|1201, 0028|1202, 0028|1203
+
+ gdcmDocEntry *e;
+ e=GetDocEntryByNumber(0x0028,0x01101);
+ if (e)
+ RemoveEntry(e);
+ e=GetDocEntryByNumber(0x0028,0x1102);
+ if (e)
+ RemoveEntry(e);
+ e=GetDocEntryByNumber(0x0028,0x1103);
+
+ if (e)
+ RemoveEntry(e);
+ e=GetDocEntryByNumber(0x0028,0x01201);
+ if (e)
+ RemoveEntry(e);
+ e=GetDocEntryByNumber(0x0028,0x1202);
+ if (e)
+ RemoveEntry(e);
+ e=GetDocEntryByNumber(0x0028,0x1203);
+ if (e)
+ RemoveEntry(e);
+ }
+
+ gdcmDocument::Write(fp,filetype);
+}
+
+//-----------------------------------------------------------------------------
+// Print
+
+
+//-----------------------------------------------------------------------------
+// Public
+
+/**
+ * \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 Dicom/Acr File.
+ * @return true when gdcmHeader is the one of a reasonable Dicom/Acr file,
+ * false otherwise.
+ */
+bool gdcmHeader::IsReadable()
+{
+ if( !gdcmDocument::IsReadable() )
+ {
+ return false;
+ }
+
+ std::string res = GetEntryByNumber(0x0028, 0x0005);
+ if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 )
+ {
+ return false; // Image Dimensions
+ }
+ if ( !GetDocEntryByNumber(0x0028, 0x0100) )
+ {
+ return false; // "Bits Allocated"
+ }
+ if ( !GetDocEntryByNumber(0x0028, 0x0101) )
+ {
+ return false; // "Bits Stored"
+ }
+ if ( !GetDocEntryByNumber(0x0028, 0x0102) )
+ {
+ return false; // "High Bit"
+ }
+ if ( !GetDocEntryByNumber(0x0028, 0x0103) )
+ {
+ return false; // "Pixel Representation" i.e. 'Sign'
+ }
+
+ return true;
+}
+
+/**
+ * \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()
+{
+ std::string strSize;
+ strSize = GetEntryByNumber(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
+ * (The ACR-NEMA file contains a Signal, not an Image).
+ */
+int gdcmHeader::GetYSize()
+{
+ std::string strSize = GetEntryByNumber(0x0028,0x0010);
+ if ( strSize != GDCM_UNFOUND )
+ {
+ return atoi( strSize.c_str() );
+ }
+ if ( IsDicomV3() )
+ {
+ return 0;
+ }
+
+ // 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;
+}
+
+/**
+ * \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 ACR-NEMA "Planes" tag content.
+ * @return The encountered size when found, 1 by default (single image).
+ */
+int gdcmHeader::GetZSize()
+{
+ // Both DicomV3 and ACR/Nema consider the "Number of Frames"
+ // as the third dimension.
+ 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
+ strSize = GetEntryByNumber(0x0028,0x0012);
+ if ( strSize != GDCM_UNFOUND )
+ {
+ return atoi( strSize.c_str() );
+ }
+
+ return 1;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief gets the info from 0028,0030 : Pixel Spacing
+ * else 1.0
+ * @return X dimension of a pixel
+ */
+float gdcmHeader::GetXSpacing()
+{
+ float xspacing, yspacing;
+ std::string strSpacing = GetEntryByNumber(0x0028,0x0030);
+
+ if ( strSpacing == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetXSpacing: unfound Pixel Spacing (0028,0030)");
+ return 1.;
+ }
+
+ int nbValues;
+ if( ( nbValues = sscanf( strSpacing.c_str(),
+ "%f\\%f", &yspacing, &xspacing)) != 2 )
+ {
+ // if single value is found, xspacing is defaulted to yspacing
+ if ( nbValues == 1 )
+ {
+ return yspacing;
+ }
+ }
+ if ( xspacing == 0.)
+ {
+ dbg.Verbose(0, "gdcmHeader::GetYSpacing: gdcmData/CT-MONO2-8-abdo.dcm problem");
+ // seems to be a bug in the header ...
+ sscanf( strSpacing.c_str(), "%f\\0\\%f", &yspacing, &xspacing);
+ }
+
+ return xspacing;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief gets the info from 0028,0030 : Pixel Spacing
+ * else 1.0
+ * @return Y dimension of a pixel
+ */
+float gdcmHeader::GetYSpacing()
+{
+ float yspacing = 0;
+ std::string strSpacing = GetEntryByNumber(0x0028,0x0030);
+
+ if ( strSpacing == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetYSpacing: unfound Pixel Spacing (0028,0030)");
+ return 1.;
+ }
+
+ // if sscanf cannot read any float value, it won't affect yspacing
+ sscanf( strSpacing.c_str(), "%f", &yspacing);
+
+ return yspacing;
+}
+
+/**
+ *\ingroup gdcmHeader
+ *\brief gets the info from 0018,0088 : Space Between Slices
+ * else from 0018,0050 : Slice Thickness
+ * else 1.0
+ * @return Z dimension of a voxel-to be
+ */
+float gdcmHeader::GetZSpacing()
+{
+ // Spacing Between Slices : distance entre le milieu de chaque coupe
+ // Les coupes peuvent etre :
+ // jointives (Spacing between Slices = Slice Thickness)
+ // chevauchantes (Spacing between Slices < Slice Thickness)
+ // disjointes (Spacing between Slices > Slice Thickness)
+ // Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal
+ // ca interesse le physicien de l'IRM, pas le visualisateur de volumes ...
+ // Si le Spacing Between Slices est absent,
+ // on suppose que les coupes sont jointives
+
+ std::string strSpacingBSlices = GetEntryByNumber(0x0018,0x0088);
+
+ if ( strSpacingBSlices == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetZSpacing: unfound StrSpacingBSlices");
+ std::string strSliceThickness = GetEntryByNumber(0x0018,0x0050);
+ if ( strSliceThickness == GDCM_UNFOUND )
+ {
+ return 1.;
+ }
+ else
+ {
+ // if no 'Spacing Between Slices' is found,
+ // we assume slices join together
+ // (no overlapping, no interslice gap)
+ // if they don't, we're fucked up
+ return atof( strSliceThickness.c_str() );
+ }
+ }
+ else
+ {
+ return atof( strSpacingBSlices.c_str() );
+ }
+}
+
+/**
+ *\ingroup gdcmHeader
+ *\brief gets the info from 0028,1052 : Rescale Intercept
+ * @return Rescale Intercept