+ DataEntry *entry = GetDataEntry(0x0018,0x1164);
+ if( entry )
+ {
+ nbValue = entry->GetValueCount();
+ // Can't use IsValueCountValid because of the complex heuristic.
+ if( nbValue >= 3 )
+ xspacing = (float)entry->GetValue(2);
+ if( nbValue >= 2 )
+ xspacing = (float)entry->GetValue(1);
+ else
+ xspacing = (float)entry->GetValue(0);
+
+ if ( xspacing == 0.0 )
+ xspacing = 1.0;
+ return xspacing;
+ }
+ else
+ {
+ gdcmWarningMacro( "Unfound Imager Pixel Spacing (0018,1164)" );
+ }
+
+ entry = GetDataEntry(0x0028,0x0030);
+ if( entry )
+ {
+ nbValue = entry->GetValueCount();
+ if( nbValue >= 3 )
+ xspacing = (float)entry->GetValue(2);
+ else if( nbValue >= 2 )
+ xspacing = (float)entry->GetValue(1);
+ else
+ xspacing = (float)entry->GetValue(0);
+
+ if ( xspacing == 0.0 )
+ xspacing = 1.0;
+ return xspacing;
+ }
+ else
+ {
+ gdcmWarningMacro( "Unfound Pixel Spacing (0028,0030)" );
+ }
+
+ return xspacing;
+}
+
+/**
+ * \brief gets the info from 0018,1164 : ImagerPixelSpacing
+ * then from 0028,0030 : Pixel Spacing
+ * else 1.0
+ * @return Y dimension of a pixel
+ */
+float File::GetYSpacing()
+{
+ float yspacing = 1.0;
+ // To follow David Clunie's advice, we first check ImagerPixelSpacing
+
+ DataEntry *entry = GetDataEntry(0x0018,0x1164);
+ if( entry )
+ {
+ yspacing = (float)entry->GetValue(0);
+
+ if ( yspacing == 0.0 )
+ yspacing = 1.0;
+ return yspacing;
+ }
+ else
+ {
+ gdcmWarningMacro( "Unfound Imager Pixel Spacing (0018,1164)" );
+ }
+
+ entry = GetDataEntry(0x0028,0x0030);
+ if( entry )
+ {
+ yspacing = (float)entry->GetValue(0);
+
+ if ( yspacing == 0.0 )
+ yspacing = 1.0;
+ return yspacing;
+ }
+ else
+ {
+ gdcmWarningMacro( "Unfound Pixel Spacing (0028,0030)" );
+ }
+
+ return yspacing;
+}
+
+/**
+ * \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 File::GetZSpacing()
+{
+ // --->
+ // ---> Warning :
+ // --->
+ // For *Dicom* images, ZSpacing should be calculated using
+ // XOrigin, YOrigin, ZOrigin (of the top left image corner)
+ // of 2 consecutive images, and the Orientation
+ //
+ // Computing ZSpacing on a single image is not really meaningfull !
+
+ float zspacing = 1.0f;
+
+ // Spacing Between Slices : distance between the middle of 2 slices
+ // Slices may be :
+ // jointives (Spacing between Slices = Slice Thickness)
+ // overlapping (Spacing between Slices < Slice Thickness)
+ // disjointes (Spacing between Slices > Slice Thickness)
+ // Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal
+ // It only concerns the MRI guys, not people wanting to visualize volumes
+ // If Spacing Between Slices is missing,
+ // we suppose slices joint together
+ DataEntry *entry = GetDataEntry(0x0018,0x0088);
+ if( entry )
+ {
+ zspacing = (float)entry->GetValue(0);
+
+ if ( zspacing == 0.0 )
+ zspacing = 1.0;
+ return zspacing;
+ }
+ else
+ gdcmWarningMacro("Unfound Spacing Between Slices (0018,0088)");
+
+ // 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
+ entry = GetDataEntry(0x0018,0x0050);
+ if( entry )
+ {
+ zspacing = (float)entry->GetValue(0);
+
+ if ( zspacing == 0.0 )
+ zspacing = 1.0;
+ return zspacing;
+ }
+ else
+ gdcmWarningMacro("Unfound Slice Thickness (0018,0050)");
+
+ return zspacing;
+}
+
+/**
+ * \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 File::GetXOrigin()
+{
+ DataEntry *entry = GetDataEntry(0x0020,0x0032);
+ if( !entry )
+ {
+ gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
+ entry = GetDataEntry(0x0020,0x0030);
+ if( !entry )
+ {
+ gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
+ return 0.0f;
+ }
+ }
+
+ if( entry->GetValueCount() == 3 )
+ {
+ if (!entry->IsValueCountValid() )
+ {
+ gdcmErrorMacro( "Invalid Value Count" );
+ }
+ return (float)entry->GetValue(0);
+ }
+ return 0.0f;
+}
+
+/**
+ * \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 File::GetYOrigin()
+{
+ DataEntry *entry = GetDataEntry(0x0020,0x0032);
+ if( !entry )
+ {
+ gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
+ entry = GetDataEntry(0x0020,0x0030);
+ if( !entry )
+ {
+ gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
+ return 0.0f;
+ }
+ }
+
+ if( entry->GetValueCount() == 3 )
+ {
+ if (!entry->IsValueCountValid() )
+ {
+ gdcmErrorMacro( "Invalid Value Count" );
+ }
+ return (float)entry->GetValue(1);
+ }
+ return 0.0f;
+}
+
+/**
+ * \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 File::GetZOrigin()
+{
+ DataEntry *entry = GetDataEntry(0x0020,0x0032);
+ if( entry )
+ {
+ if( entry->GetValueCount() == 3 )
+ {
+ if (!entry->IsValueCountValid() )
+ {
+ gdcmErrorMacro( "Invalid Value Count" );
+ }
+ return (float)entry->GetValue(2);
+ }
+ gdcmWarningMacro( "Wrong Image Position Patient (0020,0032)");
+ return 0.0f;
+ }
+
+ entry = GetDataEntry(0x0020,0x0030);
+ if( entry )
+ {
+ if( entry->GetValueCount() == 3 )
+ {
+ if (!entry->IsValueCountValid() )
+ {
+ gdcmErrorMacro( "Invalid Value Count" );
+ }
+ return (float)entry->GetValue(2);
+ }
+ gdcmWarningMacro( "Wrong Image Position (RET) (0020,0030)");
+ return 0.0f;
+ }
+
+ // for *very* old ACR-NEMA images
+ entry = GetDataEntry(0x0020,0x1041);
+ if( entry )
+ {
+ if( entry->GetValueCount() == 1 )
+ {
+ if (!entry->IsValueCountValid() )
+ {
+ gdcmErrorMacro( "Invalid Value Count" );
+ }
+ return (float)entry->GetValue(0); // VM=1 !
+ }
+ gdcmWarningMacro( "Wrong Slice Location (0020,1041)");
+ return 0.0f;
+ }
+
+ entry = GetDataEntry(0x0020,0x0050);
+ if( entry )
+ {
+ if( entry->GetValueCount() == 1 )
+ {
+ if (!entry->IsValueCountValid() )
+ {
+ gdcmErrorMacro( "Invalid Value Count" );
+ }
+ return (float)entry->GetValue(0);
+ }
+ gdcmWarningMacro( "Wrong Location (0020,0050)");
+ return 0.0f;
+ }
+ return 0.; // Hopeless
+}
+
+/**
+ * \brief gets the info from 0020,0037 : Image Orientation Patient
+ * or from 0020 0035 : Image Orientation (RET)
+ * (needed to organize DICOM files based on their x,y,z position)
+ * @param iop adress of the (6)float array to receive values
+ * @return true when one of the tag is found
+ * false when nothing is found
+ */
+bool File::GetImageOrientationPatient( float iop[6] )
+{
+ std::string strImOriPat;
+ //iop is supposed to be float[6]
+ iop[0] = iop[1] = iop[2] = iop[3] = iop[4] = iop[5] = 0.;
+
+ // 0020 0037 DS REL Image Orientation (Patient)
+ if ( (strImOriPat = GetEntryString(0x0020,0x0037)) != GDCM_UNFOUND )
+ {
+ if ( sscanf( strImOriPat.c_str(), "%f \\ %f \\%f \\%f \\%f \\%f ",
+ &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 )
+ {
+ gdcmWarningMacro( "Wrong Image Orientation Patient (0020,0037)."
+ << " Less than 6 values were found." );
+ return false;
+ }
+ }
+ //For ACR-NEMA
+ // 0020 0035 DS REL Image Orientation (RET)
+ else if ( (strImOriPat = GetEntryString(0x0020,0x0035)) != GDCM_UNFOUND )
+ {
+ if ( sscanf( strImOriPat.c_str(), "%f \\ %f \\%f \\%f \\%f \\%f ",
+ &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 )
+ {
+ gdcmWarningMacro( "wrong Image Orientation Patient (0020,0035). "
+ << "Less than 6 values were found." );
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * \brief Retrieve the number of Bits Stored (actually used)
+ * (as opposed 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 File::GetBitsStored()
+{
+ DataEntry *entry = GetDataEntry(0x0028,0x0101);
+ if( !entry )
+ {
+ gdcmWarningMacro("(0028,0101) is supposed to be mandatory");
+ return 0;
+ }
+ return (int)entry->GetValue(0);
+}
+
+/**
+ * \brief Retrieve the number of Bits Allocated
+ * (8, 12 -compacted ACR-NEMA files-, 16, 24 -old RGB ACR-NEMA files-,)
+ * @return The encountered Number of Bits Allocated, 0 by default.
+ * 0 means the file is NOT USABLE. The caller has to check it !
+ */
+int File::GetBitsAllocated()
+{
+ DataEntry *entry = GetDataEntry(0x0028,0x0100);
+ if( !entry )
+ {
+ gdcmWarningMacro("(0028,0100) is supposed to be mandatory");
+ return 0;
+ }
+ return (int)entry->GetValue(0);
+}
+
+/**
+ * \brief Retrieve the high bit position.
+ * \warning The method defaults to 0 when information is missing.
+ * The responsability of checking this value is left to the caller.
+ * @return The high bit position when present. 0 when missing.
+ */
+int File::GetHighBitPosition()
+{
+ DataEntry *entry = GetDataEntry(0x0028,0x0102);
+ if( !entry )
+ {
+ gdcmWarningMacro("(0028,0102) is supposed to be mandatory");
+ return 0;
+ }
+ return (int)entry->GetValue(0);
+}
+
+/**
+ * \brief Retrieve the number of Samples Per Pixel
+ * (1 : gray level, 3 : RGB/YBR -1 or 3 Planes-)
+ * @return The encountered number of Samples Per Pixel, 1 by default.
+ * (we assume Gray level Pixels)
+ */
+int File::GetSamplesPerPixel()
+{
+ DataEntry *entry = GetDataEntry(0x0028,0x0002);
+ if( !entry )
+ {
+ gdcmWarningMacro("(0028,0002) is supposed to be mandatory");
+ return 1; // Well, it's supposed to be mandatory ...
+ // but sometimes it's missing : *we* assume Gray pixels
+ }
+ return (int)entry->GetValue(0);
+}
+
+/**
+ * \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 File::GetPlanarConfiguration()
+{
+ DataEntry *entry = GetDataEntry(0x0028,0x0006);
+ if( !entry )
+ {
+ return 0;
+ }
+ return (int)entry->GetValue(0);
+}
+
+/**
+ * \brief 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 File::GetPixelSize()
+{
+ // 0028 0100 US IMG Bits Allocated
+ // (in order no to be messed up by old ACR-NEMA RGB images)
+ assert( !(GetEntryString(0x0028,0x0100) == "24") );
+
+ 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;
+ }
+ if ( pixelType == "FD" )
+ {
+ return 8;
+ }
+ gdcmWarningMacro( "Unknown pixel type: " << pixelType);
+ return 0;
+}
+
+/**
+ * \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,
+ * - FD floating double 64 bits (Not kosher DICOM, but so usefull!)
+ * \warning 12 bit images appear as 16 bit.
+ * 24 bit images appear as 8 bit + photochromatic interp ="RGB "
+ * + Planar Configuration = 0
+ * @return 0S if nothing found. NOT USABLE file. The caller has to check
+ */
+std::string File::GetPixelType()
+{
+ std::string bitsAlloc = GetEntryString(0x0028, 0x0100); // Bits Allocated
+ if ( bitsAlloc == GDCM_UNFOUND )
+ {
+ gdcmWarningMacro( "Missing Bits Allocated (0028,0100)");
+ bitsAlloc = "16"; // default and arbitrary value, not to polute the output
+ }
+
+ if ( bitsAlloc == "64" )
+ {
+ return "FD";
+ }
+ else if ( bitsAlloc == "12" )
+ {
+ // It will be unpacked
+ bitsAlloc = "16";
+ }
+ else if ( bitsAlloc == "24" )
+ {
+ // (in order no to be messed up by old RGB images)
+ bitsAlloc = "8";
+ }
+
+ std::string sign;
+ if( IsSignedPixelData() )
+ {
+ sign = "S";
+ }
+ else
+ {
+ sign = "U";
+ }
+ return bitsAlloc + sign;
+}
+
+/**
+ * \brief Check whether the pixels are signed (1) or UNsigned (0) data.
+ * \warning The method defaults to false (UNsigned) when tag 0028|0103
+ * is missing.
+ * The responsability of checking this value is left to the caller
+ * (NO transformation is performed on the pixels to make then >0)
+ * @return True when signed, false when UNsigned
+ */
+bool File::IsSignedPixelData()
+{
+ DataEntry *entry = GetDataEntry(0x0028, 0x0103);//"Pixel Representation"
+ if( !entry )
+ {
+ gdcmWarningMacro( "Missing Pixel Representation (0028,0103)");
+ return false;
+ }
+ return entry->GetValue(0) != 0;
+}
+
+/**
+ * \brief Check whether this a monochrome picture (gray levels) or not,
+ * using "Photometric Interpretation" tag (0x0028,0x0004).
+ * @return true when "MONOCHROME1" or "MONOCHROME2". False otherwise.
+ */
+bool File::IsMonochrome()
+{
+ const std::string &PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
+ if ( Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1")
+ || Util::DicomStringEqual(PhotometricInterp, "MONOCHROME2") )
+ {
+ return true;
+ }
+ if ( PhotometricInterp == GDCM_UNFOUND )
+ {
+ gdcmWarningMacro( "Not found : Photometric Interpretation (0028,0004)");
+ }
+ return false;
+}
+
+/**
+ * \brief Check whether this a MONOCHROME1 picture (high values = dark)
+ * or not using "Photometric Interpretation" tag (0x0028,0x0004).
+ * @return true when "MONOCHROME1" . False otherwise.
+ */
+bool File::IsMonochrome1()
+{
+ const std::string &PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
+ if ( Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1") )
+ {
+ return true;
+ }
+ if ( PhotometricInterp == GDCM_UNFOUND )
+ {
+ gdcmWarningMacro( "Not found : Photometric Interpretation (0028,0004)");
+ }
+ return false;
+}
+
+/**
+ * \brief Check whether this a "PALETTE COLOR" picture or not by accessing
+ * the "Photometric Interpretation" tag ( 0x0028, 0x0004 ).
+ * @return true when "PALETTE COLOR". False otherwise.
+ */
+bool File::IsPaletteColor()
+{
+ std::string PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
+ if ( PhotometricInterp == "PALETTE COLOR " )
+ {
+ return true;
+ }
+ if ( PhotometricInterp == GDCM_UNFOUND )
+ {
+ gdcmWarningMacro( "Not found : Palette color (0028,0004)");
+ }
+ return false;
+}
+
+/**
+ * \brief Check whether this a "YBR_FULL" color picture or not by accessing
+ * the "Photometric Interpretation" tag ( 0x0028, 0x0004 ).
+ * @return true when "YBR_FULL". False otherwise.
+ */
+bool File::IsYBRFull()
+{
+ std::string PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
+ if ( PhotometricInterp == "YBR_FULL" )
+ {
+ return true;
+ }
+ if ( PhotometricInterp == GDCM_UNFOUND )
+ {
+ gdcmWarningMacro( "Not found : YBR Full (0028,0004)");
+ }
+ return false;
+}
+
+/**
+ * \brief tells us if LUT are used
+ * \warning Right now, 'Segmented xxx Palette Color Lookup Table Data'
+ * are NOT considered as LUT, since nobody knows
+ * how to deal with them
+ * Please warn me if you know sbdy that *does* know ... jprx
+ * @return true if LUT Descriptors and LUT Tables were found
+ */
+bool File::HasLUT()
+{
+ // Check the presence of the LUT Descriptors, and LUT Tables
+ // LutDescriptorRed
+ if ( !GetDocEntry(0x0028,0x1101) )
+ {
+ return false;
+ }
+ // LutDescriptorGreen
+ if ( !GetDocEntry(0x0028,0x1102) )
+ {
+ return false;
+ }
+ // LutDescriptorBlue
+ if ( !GetDocEntry(0x0028,0x1103) )
+ {
+ return false;
+ }
+ // Red Palette Color Lookup Table Data
+ if ( !GetDocEntry(0x0028,0x1201) )
+ {
+ return false;
+ }
+ // Green Palette Color Lookup Table Data
+ if ( !GetDocEntry(0x0028,0x1202) )
+ {
+ return false;
+ }
+ // Blue Palette Color Lookup Table Data
+ if ( !GetDocEntry(0x0028,0x1203) )
+ {
+ return false;
+ }
+
+ // FIXME : (0x0028,0x3006) : LUT Data (CTX dependent)
+ // NOT taken into account, but we don't know how to use it ...
+ return true;
+}
+
+/**
+ * \brief gets the info from 0028,1101 : Lookup Table Desc-Red
+ * else 0
+ * @return Lookup Table number of Bits , 0 by default
+ * when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
+ * @ return bit number of each LUT item
+ */
+int File::GetLUTNbits()
+{
+ std::vector<std::string> tokens;
+ int lutNbits;
+
+ //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red
+ // = Lookup Table Desc-Blue
+ // Consistency already checked in GetLUTLength
+ std::string lutDescription = GetEntryString(0x0028,0x1101);
+ if ( lutDescription == GDCM_UNFOUND )
+ {
+ return 0;
+ }
+
+ tokens.clear(); // clean any previous value
+ Util::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;
+}
+
+/**
+ *\brief gets the info from 0028,1052 : Rescale Intercept
+ * @return Rescale Intercept
+ */
+float File::GetRescaleIntercept()
+{
+ // 0028 1052 DS IMG Rescale Intercept
+ DataEntry *entry = GetDataEntry(0x0028, 0x1052);
+ if( !entry )
+ {
+ gdcmWarningMacro( "Missing Rescale Intercept (0028,1052)");
+ return 0.0f;
+ }
+ return (float)entry->GetValue(0);
+
+}
+
+/**
+ *\brief gets the info from 0028,1053 : Rescale Slope
+ * @return Rescale Slope
+ */
+float File::GetRescaleSlope()
+{
+ // 0028 1053 DS IMG Rescale Slope
+ DataEntry *entry = GetDataEntry(0x0028, 0x1053);
+ if( !entry )
+ {
+ gdcmWarningMacro( "Missing Rescale Slope (0028,1053)");
+ return 1.0f;
+ }
+ return (float)entry->GetValue(0);
+}
+
+/**
+ * \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 File::GetNumberOfScalarComponents()
+{
+ if ( GetSamplesPerPixel() == 3 )
+ {
+ return 3;
+ }
+
+ // 0028 0100 US IMG Bits Allocated
+ // (in order no to be messed up by old RGB images)
+ if ( GetEntryString(0x0028,0x0100) == "24" )
+ {
+ return 3;
+ }
+
+ std::string strPhotometricInterpretation = GetEntryString(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 ||
+ Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME1") ||
+ Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME2") )
+ {
+ return 1;
+ }
+ else
+ {
+ // we assume that *all* kinds of YBR are dealt with
+ return 3;
+ }
+}
+
+/**
+ * \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 File::GetNumberOfScalarComponentsRaw()
+{
+ // 0028 0100 US IMG Bits Allocated
+ // (in order no to be messed up by old RGB images)
+ if ( File::GetEntryString(0x0028,0x0100) == "24" )
+ {
+ return 3;
+ }
+
+ // we assume that *all* kinds of YBR are dealt with
+ return GetSamplesPerPixel();
+}
+
+/**
+ * \brief Recover the offset (from the beginning of the file)
+ * of *image* pixels (not *icone image* pixels, if any !)
+ * @return Pixel Offset
+ */
+size_t File::GetPixelOffset()
+{
+ DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel);
+ if ( pxlElement )
+ {
+ return pxlElement->GetOffset();
+ }
+ else
+ {
+ gdcmDebugMacro( "Big trouble : Pixel Element ("
+ << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" );
+ return 0;
+ }
+}
+
+/**
+ * \brief Recover the pixel area length (in Bytes)
+ * @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 File::GetPixelAreaLength()
+{
+ DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel);
+ if ( pxlElement )
+ {
+ return pxlElement->GetLength();
+ }
+ else
+ {
+ gdcmDebugMacro( "Big trouble : Pixel Element ("
+ << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" );
+ return 0;
+ }
+}
+
+/**
+ * \brief Adds the characteristics of a new element we want to anonymize
+ * @param group Group number of the target tag.
+ * @param elem Element number of the target tag.
+ * @param value new value (string) to substitute with
+ */
+void File::AddAnonymizeElement (uint16_t group, uint16_t elem,
+ std::string const &value)
+{
+ DicomElement el;
+ el.Group = group;
+ el.Elem = elem;
+ el.Value = value;
+ UserAnonymizeList.push_back(el);
+}
+
+/**
+ * \brief Overwrites in the file the values of the DicomElements
+ * held in the list
+ */
+void File::AnonymizeNoLoad()
+{
+ std::fstream *fp = new std::fstream(Filename.c_str(),
+ std::ios::in | std::ios::out | std::ios::binary);
+ gdcm::DocEntry *d;
+ uint32_t offset;
+ uint32_t lgth;
+ uint32_t valLgth = 0;
+ std::string *spaces;
+ for (ListElements::iterator it = UserAnonymizeList.begin();
+ it != UserAnonymizeList.end();
+ ++it)
+ {
+ d = GetDocEntry( (*it).Group, (*it).Elem);
+
+ if ( d == NULL)
+ continue;
+
+ if ( dynamic_cast<SeqEntry *>(d) )
+ {
+ gdcmWarningMacro( "You cannot 'Anonymize' a SeqEntry ");
+ continue;
+ }
+
+ offset = d->GetOffset();
+ lgth = d->GetLength();
+ if (valLgth < lgth)
+ {
+ spaces = new std::string( lgth-valLgth, ' ');
+ (*it).Value = (*it).Value + *spaces;
+ delete spaces;
+ }
+ fp->seekp( offset, std::ios::beg );
+ fp->write( (*it).Value.c_str(), lgth );
+
+ }
+ fp->close();
+ delete fp;
+}
+
+/**
+ * \brief anonymize a File (remove Patient's personal info passed with
+ * AddAnonymizeElement()
+ * \note You cannot Anonymize a DataEntry (to be fixed)
+ */
+bool File::AnonymizeFile()
+{
+ // If Anonymisation list is empty, let's perform some basic anonymization
+ if ( UserAnonymizeList.begin() == UserAnonymizeList.end() )
+ {
+ // If exist, replace by spaces
+ SetEntryString(" ",0x0010, 0x2154); // Telephone
+ SetEntryString(" ",0x0010, 0x1040); // Adress
+ SetEntryString(" ",0x0010, 0x0020); // Patient ID
+
+ DocEntry *patientNameHE = GetDocEntry (0x0010, 0x0010);