]> Creatis software - gdcm.git/blobdiff - src/gdcmFile.cxx
*** empty log message ***
[gdcm.git] / src / gdcmFile.cxx
index 4adfcd303d266e474491c21912091fd480a07701..0b31c5ceeb8f72673aa04a509621f78af1693aad 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmFile.cxx,v $
   Language:  C++
-  Date:      $Date: 2005/01/21 12:37:15 $
-  Version:   $Revision: 1.196 $
+  Date:      $Date: 2005/02/02 10:02:17 $
+  Version:   $Revision: 1.207 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
 #include "gdcmTS.h"
 #include "gdcmValEntry.h"
 #include "gdcmBinEntry.h"
-#include <stdio.h> //sscanf
+#include "gdcmRLEFramesInfo.h"
+#include "gdcmJPEGFragmentsInfo.h"
 
+#include <stdio.h> //sscanf
 #include <vector>
 
 namespace gdcm 
@@ -35,9 +37,12 @@ namespace gdcm
  * \brief  Constructor 
  * @param  filename name of the file whose header we want to analyze
  */
-File::File( std::string const &filename ):
-            Document( filename )
+File::File( std::string const &filename )
+     :Document( filename )
 {    
+   RLEInfo  = new RLEFramesInfo;
+   JPEGInfo = new JPEGFragmentsInfo;
+
    // for some ACR-NEMA images GrPixel, NumPixel is *not* 7fe0,0010
    // We may encounter the 'RETired' (0x0028, 0x0200) tag
    // (Image Location") . This entry contains the number of
@@ -45,11 +50,11 @@ File::File( std::string const &filename ):
    // 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 Missing we default to group 0x7fe0.
+   // When the "Image Location" is missing we default to group 0x7fe0.
    // Note: this IS the right place for the code
  
    // Image Location
-   const std::string &imgLocation = GetEntry(0x0028, 0x0200);
+   const std::string &imgLocation = GetEntryValue(0x0028, 0x0200);
    if ( imgLocation == GDCM_UNFOUND )
    {
       // default value
@@ -60,9 +65,9 @@ File::File( std::string const &filename ):
       GrPixel = (uint16_t) atoi( imgLocation.c_str() );
    }   
 
-   // sometimes Image Location value doesn't follow 
-   // the supposed processor endianness. 
-   // see gdcmData/cr172241.dcm      
+   // sometimes Image Location value doesn't follow
+   // the supposed processor endianness.
+   // see gdcmData/cr172241.dcm
    if ( GrPixel == 0xe07f )
    {
       GrPixel = 0x7fe0;
@@ -84,29 +89,58 @@ File::File( std::string const &filename ):
    DocEntry *entry = GetDocEntry(GrPixel, NumPixel); 
    if ( entry != 0 )
    {
-
-      std::string PixelVR;
-      // 8 bits allocated is a 'O Bytes' , as well as 24 (old ACR-NEMA RGB)
-      // more than 8 (i.e 12, 16) is a 'O Words'
-      if ( GetBitsAllocated() == 8 || GetBitsAllocated() == 24 ) 
-         PixelVR = "OB";
-      else
-         PixelVR = "OW";
-
-      DictEntry* newEntry = NewVirtualDictEntry(
-                             GrPixel, NumPixel,
-                             PixelVR, "PXL", "Pixel Data");
-      entry->SetDictEntry( newEntry );
+      // Compute the RLE or JPEG info
+      OpenFile();
+      std::string ts = GetTransferSyntax();
+      Fp->seekg( entry->GetOffset(), std::ios::beg );
+      if ( Global::GetTS()->IsRLELossless(ts) ) 
+         ComputeRLEInfo();
+      else if ( Global::GetTS()->IsJPEG(ts) )
+         ComputeJPEGFragmentInfo();
+      CloseFile();
+
+      // Create a new BinEntry to change the the DictEntry
+      // The changed DictEntry will have 
+      // - a correct PixelVR OB or OW)
+      // - a VM to "PXL"
+      // - the name to "Pixel Data"
+      BinEntry *oldEntry = dynamic_cast<BinEntry *>(entry);
+      if(oldEntry)
+      {
+         std::string PixelVR;
+         // 8 bits allocated is a 'O Bytes' , as well as 24 (old ACR-NEMA RGB)
+         // more than 8 (i.e 12, 16) is a 'O Words'
+         if ( GetBitsAllocated() == 8 || GetBitsAllocated() == 24 ) 
+            PixelVR = "OB";
+         else
+            PixelVR = "OW";
+
+         // Change only made if usefull
+         if( PixelVR != oldEntry->GetVR() )
+         {
+            DictEntry* newDict = NewVirtualDictEntry(GrPixel,NumPixel,
+                                                     PixelVR,"1","Pixel Data");
+
+            BinEntry *newEntry = new BinEntry(newDict);
+            newEntry->Copy(entry);
+            newEntry->SetBinArea(oldEntry->GetBinArea(),oldEntry->IsSelfArea());
+            oldEntry->SetSelfArea(false);
+
+            RemoveEntry(oldEntry);
+            AddEntry(newEntry);
+         }
+      }
    }
 }
 
 /**
  * \brief Constructor used when we want to generate dicom files from scratch
  */
-File::File()
-           :Document()
+File::File():
+   Document()
 {
+   RLEInfo  = new RLEFramesInfo;
+   JPEGInfo = new JPEGFragmentsInfo;
    InitializeDefaultFile();
 }
 
@@ -115,15 +149,21 @@ File::File()
  */
 File::~File ()
 {
+   if( RLEInfo )
+      delete RLEInfo;
+   if( JPEGInfo )
+      delete JPEGInfo;
 }
 
+//-----------------------------------------------------------------------------
+// Public
 /**
  * \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 fileName file name to write to
  * @param filetype Type of the File to be written 
- *          (ACR-NEMA, ExplicitVR, ImplicitVR)
+ *          (ACR, ExplicitVR, ImplicitVR)
  */
 bool File::Write(std::string fileName, FileType filetype)
 {
@@ -135,13 +175,20 @@ bool File::Write(std::string fileName, FileType filetype)
       return false;
    }
 
-   // Bits Allocated
-   if ( GetEntry(0x0028,0x0100) ==  "12")
+   // Entry : 0002|0000 = group length -> recalculated
+   ValEntry *e0002 = GetValEntry(0x0002,0x0000);
+   if( e0002 )
    {
-      SetEntry("16", 0x0028,0x0100);
+      std::ostringstream sLen;
+      sLen << ComputeGroup0002Length(filetype);
+      e0002->SetValue(sLen.str());
    }
 
-  /// \todo correct 'Pixel group' Length if necessary
+   // Bits Allocated
+   if ( GetEntryValue(0x0028,0x0100) ==  "12")
+   {
+      SetValEntry("16", 0x0028,0x0100);
+   }
 
    int i_lgPix = GetEntryLength(GrPixel, NumPixel);
    if (i_lgPix != -2)
@@ -149,15 +196,14 @@ bool File::Write(std::string fileName, FileType filetype)
       // no (GrPixel, NumPixel) element
       std::string s_lgPix = Util::Format("%d", i_lgPix+12);
       s_lgPix = Util::DicomString( s_lgPix.c_str() );
-      ReplaceOrCreate(s_lgPix,GrPixel, 0x0000);
+      InsertValEntry(s_lgPix,GrPixel, 0x0000);
    }
 
    // FIXME : should be nice if we could move it to File
    //         (or in future gdcmPixelData class)
 
    // Drop Palette Color, if necessary
-   
-   if ( GetEntry(0x0028,0x0002).c_str()[0] == '3' )
+   if ( GetEntryValue(0x0028,0x0002).c_str()[0] == '3' )
    {
       // if SamplesPerPixel = 3, sure we don't need any LUT !   
       // Drop 0028|1101, 0028|1102, 0028|1103
@@ -202,7 +248,7 @@ bool File::Write(std::string fileName, FileType filetype)
    BinEntry *b = GetBinEntry(GrPixel,NumPixel);
    if ( GetPixelSize() ==  16 )
    {
-      uint16_t *im16 = (uint16_t*)b->GetBinArea();
+      uint16_t *im16 = (uint16_t *)b->GetBinArea();
       int lgr = b->GetLength();
       for( int i = 0; i < lgr / 2; i++ )
       {
@@ -212,7 +258,7 @@ bool File::Write(std::string fileName, FileType filetype)
 #endif //GDCM_WORDS_BIGENDIAN
 */
 
-   Document::WriteContent(fp,filetype);
+   Document::WriteContent(fp, filetype);
 
 /*
 #ifdef GDCM_WORDS_BIGENDIAN
@@ -235,13 +281,6 @@ bool File::Write(std::string fileName, FileType filetype)
    return true;
 }
 
-//-----------------------------------------------------------------------------
-// Print
-
-
-//-----------------------------------------------------------------------------
-// Public
-
 /**
  * \brief  This predicate, based on hopefully reasonable heuristics,
  *         decides whether or not the current File was properly parsed
@@ -257,7 +296,7 @@ bool File::IsReadable()
       return false;
    }
 
-   const std::string &res = GetEntry(0x0028, 0x0005);
+   const std::string &res = GetEntryValue(0x0028, 0x0005);
    if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 )
    {
       return false; // Image Dimensions
@@ -289,7 +328,7 @@ bool File::IsReadable()
  */
 int File::GetXSize()
 {
-   const std::string &strSize = GetEntry(0x0028,0x0011);
+   const std::string &strSize = GetEntryValue(0x0028,0x0011);
    if ( strSize == GDCM_UNFOUND )
    {
       return 0;
@@ -306,7 +345,7 @@ int File::GetXSize()
  */
 int File::GetYSize()
 {
-   const std::string &strSize = GetEntry(0x0028,0x0010);
+   const std::string &strSize = GetEntryValue(0x0028,0x0010);
    if ( strSize != GDCM_UNFOUND )
    {
       return atoi( strSize.c_str() );
@@ -333,14 +372,14 @@ int File::GetZSize()
 {
    // Both  DicomV3 and ACR/Nema consider the "Number of Frames"
    // as the third dimension.
-   const std::string &strSize = GetEntry(0x0028,0x0008);
+   const std::string &strSize = GetEntryValue(0x0028,0x0008);
    if ( strSize != GDCM_UNFOUND )
    {
       return atoi( strSize.c_str() );
    }
 
    // We then consider the "Planes" entry as the third dimension 
-   const std::string &strSize2 = GetEntry(0x0028,0x0012);
+   const std::string &strSize2 = GetEntryValue(0x0028,0x0012);
    if ( strSize2 != GDCM_UNFOUND )
    {
       return atoi( strSize2.c_str() );
@@ -357,7 +396,7 @@ int File::GetZSize()
 float File::GetXSpacing()
 {
    float xspacing, yspacing;
-   const std::string &strSpacing = GetEntry(0x0028,0x0030);
+   const std::string &strSpacing = GetEntryValue(0x0028,0x0030);
 
    if ( strSpacing == GDCM_UNFOUND )
    {
@@ -405,7 +444,7 @@ float File::GetXSpacing()
 float File::GetYSpacing()
 {
    float yspacing = 1.;
-   std::string strSpacing = GetEntry(0x0028,0x0030);
+   std::string strSpacing = GetEntryValue(0x0028,0x0030);
   
    if ( strSpacing == GDCM_UNFOUND )
    {
@@ -440,12 +479,12 @@ float File::GetZSpacing()
    //   Si le Spacing Between Slices est Missing, 
    //   on suppose que les coupes sont jointives
    
-   const std::string &strSpacingBSlices = GetEntry(0x0018,0x0088);
+   const std::string &strSpacingBSlices = GetEntryValue(0x0018,0x0088);
 
    if ( strSpacingBSlices == GDCM_UNFOUND )
    {
       gdcmVerboseMacro("Unfound Spacing Between Slices (0018,0088)");
-      const std::string &strSliceThickness = GetEntry(0x0018,0x0050);       
+      const std::string &strSliceThickness = GetEntryValue(0x0018,0x0050);       
       if ( strSliceThickness == GDCM_UNFOUND )
       {
          gdcmVerboseMacro("Unfound Slice Thickness (0018,0050)");
@@ -472,7 +511,7 @@ float File::GetRescaleIntercept()
 {
    float resInter = 0.;
    /// 0028 1052 DS IMG Rescale Intercept
-   const std::string &strRescInter = GetEntry(0x0028,0x1052);
+   const std::string &strRescInter = GetEntryValue(0x0028,0x1052);
    if ( strRescInter != GDCM_UNFOUND )
    {
       if( sscanf( strRescInter.c_str(), "%f", &resInter) != 1 )
@@ -493,7 +532,7 @@ float File::GetRescaleSlope()
 {
    float resSlope = 1.;
    //0028 1053 DS IMG Rescale Slope
-   std::string strRescSlope = GetEntry(0x0028,0x1053);
+   std::string strRescSlope = GetEntryValue(0x0028,0x1053);
    if ( strRescSlope != GDCM_UNFOUND )
    {
       if( sscanf( strRescSlope.c_str(), "%f", &resSlope) != 1)
@@ -522,12 +561,12 @@ int File::GetNumberOfScalarComponents()
       
    // 0028 0100 US IMG Bits Allocated
    // (in order no to be messed up by old RGB images)
-   if ( GetEntry(0x0028,0x0100) == "24" )
+   if ( GetEntryValue(0x0028,0x0100) == "24" )
    {
       return 3;
    }
        
-   std::string strPhotometricInterpretation = GetEntry(0x0028,0x0004);
+   std::string strPhotometricInterpretation = GetEntryValue(0x0028,0x0004);
 
    if ( ( strPhotometricInterpretation == "PALETTE COLOR ") )
    {
@@ -567,7 +606,7 @@ int File::GetNumberOfScalarComponentsRaw()
 {
    // 0028 0100 US IMG Bits Allocated
    // (in order no to be messed up by old RGB images)
-   if ( File::GetEntry(0x0028,0x0100) == "24" )
+   if ( File::GetEntryValue(0x0028,0x0100) == "24" )
    {
       return 3;
    }
@@ -585,9 +624,6 @@ int File::GetNumberOfScalarComponentsRaw()
 //                                   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?
 //
 // ---------------------------------------------------------------
 //
@@ -601,16 +637,15 @@ int File::GetNumberOfScalarComponentsRaw()
 float File::GetXOrigin()
 {
    float xImPos, yImPos, zImPos;  
-   std::string strImPos = GetEntry(0x0020,0x0032);
+   std::string strImPos = GetEntryValue(0x0020,0x0032);
 
    if ( strImPos == GDCM_UNFOUND )
    {
       gdcmVerboseMacro( "Unfound Image Position Patient (0020,0032)");
-      strImPos = GetEntry(0x0020,0x0030); // For ACR-NEMA images
+      strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images
       if ( strImPos == GDCM_UNFOUND )
       {
          gdcmVerboseMacro( "Unfound Image Position (RET) (0020,0030)");
-         /// \todo How to tell the caller nothing was found ?
          return 0.;
       }
    }
@@ -632,16 +667,15 @@ float File::GetXOrigin()
 float File::GetYOrigin()
 {
    float xImPos, yImPos, zImPos;
-   std::string strImPos = GetEntry(0x0020,0x0032);
+   std::string strImPos = GetEntryValue(0x0020,0x0032);
 
    if ( strImPos == GDCM_UNFOUND)
    {
       gdcmVerboseMacro( "Unfound Image Position Patient (0020,0032)");
-      strImPos = GetEntry(0x0020,0x0030); // For ACR-NEMA images
+      strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images
       if ( strImPos == GDCM_UNFOUND )
       {
          gdcmVerboseMacro( "Unfound Image Position (RET) (0020,0030)");
-         /// \todo How to tell the caller nothing was found ?
          return 0.;
       }  
    }
@@ -665,7 +699,7 @@ float File::GetYOrigin()
 float File::GetZOrigin()
 {
    float xImPos, yImPos, zImPos; 
-   std::string strImPos = GetEntry(0x0020,0x0032);
+   std::string strImPos = GetEntryValue(0x0020,0x0032);
 
    if ( strImPos != GDCM_UNFOUND )
    {
@@ -680,7 +714,7 @@ float File::GetZOrigin()
       }
    }
 
-   strImPos = GetEntry(0x0020,0x0030); // For ACR-NEMA images
+   strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images
    if ( strImPos != GDCM_UNFOUND )
    {
       if( sscanf( strImPos.c_str(), 
@@ -695,7 +729,7 @@ float File::GetZOrigin()
       }
    }
 
-   std::string strSliceLocation = GetEntry(0x0020,0x1041); // for *very* old ACR-NEMA images
+   std::string strSliceLocation = GetEntryValue(0x0020,0x1041); // for *very* old ACR-NEMA images
    if ( strSliceLocation != GDCM_UNFOUND )
    {
       if( sscanf( strSliceLocation.c_str(), "%f", &zImPos) != 1)
@@ -710,7 +744,7 @@ float File::GetZOrigin()
    }
    gdcmVerboseMacro( "Unfound Slice Location (0020,1041)");
 
-   std::string strLocation = GetEntry(0x0020,0x0050);
+   std::string strLocation = GetEntryValue(0x0020,0x0050);
    if ( strLocation != GDCM_UNFOUND )
    {
       if( sscanf( strLocation.c_str(), "%f", &zImPos) != 1)
@@ -741,7 +775,7 @@ int File::GetImageNumber()
    // faster function. sscanf() can do all possible conversions whereas
    // atoi() can only do single decimal integer conversions.
    //0020 0013 IS REL Image Number
-   std::string strImNumber = GetEntry(0x0020,0x0013);
+   std::string strImNumber = GetEntryValue(0x0020,0x0013);
    if ( strImNumber != GDCM_UNFOUND )
    {
       return atoi( strImNumber.c_str() );
@@ -756,7 +790,7 @@ int File::GetImageNumber()
 ModalityType File::GetModality()
 {
    // 0008 0060 CS ID Modality
-   std::string strModality = GetEntry(0x0008,0x0060);
+   std::string strModality = GetEntryValue(0x0008,0x0060);
    if ( strModality != GDCM_UNFOUND )
    {
            if ( strModality.find("AU") < strModality.length()) return AU;
@@ -819,7 +853,7 @@ ModalityType File::GetModality()
  */
 int File::GetBitsStored()
 {
-   std::string strSize = GetEntry( 0x0028, 0x0101 );
+   std::string strSize = GetEntryValue( 0x0028, 0x0101 );
    if ( strSize == GDCM_UNFOUND )
    {
       gdcmVerboseMacro("(0028,0101) is supposed to be mandatory");
@@ -837,7 +871,7 @@ int File::GetBitsStored()
  */
 int File::GetHighBitPosition()
 {
-   std::string strSize = GetEntry( 0x0028, 0x0102 );
+   std::string strSize = GetEntryValue( 0x0028, 0x0102 );
    if ( strSize == GDCM_UNFOUND )
    {
       gdcmVerboseMacro( "(0028,0102) is supposed to be mandatory");
@@ -854,7 +888,7 @@ int File::GetHighBitPosition()
  */
 bool File::IsSignedPixelData()
 {
-   std::string strSize = GetEntry( 0x0028, 0x0103 );
+   std::string strSize = GetEntryValue( 0x0028, 0x0103 );
    if ( strSize == GDCM_UNFOUND )
    {
       gdcmVerboseMacro( "(0028,0103) is supposed to be mandatory");
@@ -876,7 +910,7 @@ bool File::IsSignedPixelData()
  */
 int File::GetBitsAllocated()
 {
-   std::string strSize = GetEntry(0x0028,0x0100);
+   std::string strSize = GetEntryValue(0x0028,0x0100);
    if ( strSize == GDCM_UNFOUND )
    {
       gdcmVerboseMacro( "(0028,0100) is supposed to be mandatory");
@@ -894,7 +928,7 @@ int File::GetBitsAllocated()
  */
 int File::GetSamplesPerPixel()
 {
-   const std::string& strSize = GetEntry(0x0028,0x0002);
+   const std::string &strSize = GetEntryValue(0x0028,0x0002);
    if ( strSize == GDCM_UNFOUND )
    {
       gdcmVerboseMacro( "(0028,0002) is supposed to be mandatory");
@@ -911,7 +945,7 @@ int File::GetSamplesPerPixel()
  */
 bool File::IsMonochrome()
 {
-   const std::string& PhotometricInterp = GetEntry( 0x0028, 0x0004 );
+   const std::string &PhotometricInterp = GetEntryValue( 0x0028, 0x0004 );
    if (  Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1")
       || Util::DicomStringEqual(PhotometricInterp, "MONOCHROME2") )
    {
@@ -931,7 +965,7 @@ bool File::IsMonochrome()
  */
 bool File::IsPaletteColor()
 {
-   std::string PhotometricInterp = GetEntry( 0x0028, 0x0004 );
+   std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 );
    if (   PhotometricInterp == "PALETTE COLOR " )
    {
       return true;
@@ -950,7 +984,7 @@ bool File::IsPaletteColor()
  */
 bool File::IsYBRFull()
 {
-   std::string PhotometricInterp = GetEntry( 0x0028, 0x0004 );
+   std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 );
    if (   PhotometricInterp == "YBR_FULL" )
    {
       return true;
@@ -969,7 +1003,7 @@ bool File::IsYBRFull()
  */
 int File::GetPlanarConfiguration()
 {
-   std::string strSize = GetEntry(0x0028,0x0006);
+   std::string strSize = GetEntryValue(0x0028,0x0006);
    if ( strSize == GDCM_UNFOUND )
    {
       gdcmVerboseMacro( "Not found : Planar Configuration (0028,0006)");
@@ -987,7 +1021,7 @@ int File::GetPixelSize()
 {
    // 0028 0100 US IMG Bits Allocated
    // (in order no to be messed up by old RGB images)
-   //   if (File::GetEntry(0x0028,0x0100) == "24")
+   //   if (File::GetEntryValue(0x0028,0x0100) == "24")
    //      return 3;
 
    std::string pixelType = GetPixelType();
@@ -1027,7 +1061,7 @@ int File::GetPixelSize()
  */
 std::string File::GetPixelType()
 {
-   std::string bitsAlloc = GetEntry(0x0028, 0x0100); // Bits Allocated
+   std::string bitsAlloc = GetEntryValue(0x0028, 0x0100); // Bits Allocated
    if ( bitsAlloc == GDCM_UNFOUND )
    {
       gdcmVerboseMacro( "Missing  Bits Allocated (0028,0100)");
@@ -1049,7 +1083,7 @@ std::string File::GetPixelType()
       bitsAlloc = "8";  // by old RGB images)
    }
 
-   std::string sign = GetEntry(0x0028, 0x0103);//"Pixel Representation"
+   std::string sign = GetEntryValue(0x0028, 0x0103);//"Pixel Representation"
 
    if (sign == GDCM_UNFOUND )
    {
@@ -1091,7 +1125,6 @@ size_t File::GetPixelOffset()
    }
 }
 
-/// \todo TODO : unify those two (previous one and next one)
 /**
  * \brief   Recover the pixel area length (in Bytes)
  * @return Pixel Element Length, as stored in the header
@@ -1179,7 +1212,7 @@ int File::GetLUTNbits()
    //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red
    //                                = Lookup Table Desc-Blue
    // Consistency already checked in GetLUTLength
-   std::string lutDescription = GetEntry(0x0028,0x1101);
+   std::string lutDescription = GetEntryValue(0x0028,0x1101);
    if ( lutDescription == GDCM_UNFOUND )
    {
       return 0;
@@ -1196,9 +1229,38 @@ int File::GetLUTNbits()
    return lutNbits;
 }
 
+/**
+  * \brief gets the info from 0020,0037 : Image Orientation Patient
+  * (needed to organize DICOM files based on their x,y,z position)
+  * @param iop adress of the (6)float aray to receive values
+  * @return cosines of image orientation patient
+  */
+void 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.;
 
-//-----------------------------------------------------------------------------
-// Protected
+   // 0020 0037 DS REL Image Orientation (Patient)
+   if ( (strImOriPat = GetEntryValue(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 )
+      {
+         gdcmVerboseMacro( "Wrong Image Orientation Patient (0020,0037). Less than 6 values were found." );
+      }
+   }
+   //For ACR-NEMA
+   // 0020 0035 DS REL Image Orientation (RET)
+   else if ( (strImOriPat = GetEntryValue(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 )
+      {
+         gdcmVerboseMacro( "wrong Image Orientation Patient (0020,0035). Less than 6 values were found." );
+      }
+   }
+}
 
 /**
  * \brief anonymize a File (removes Patient's personal info)
@@ -1207,22 +1269,22 @@ int File::GetLUTNbits()
 bool File::AnonymizeFile()
 {
    // If exist, replace by spaces
-   SetEntry ("  ",0x0010, 0x2154); // Telephone   
-   SetEntry ("  ",0x0010, 0x1040); // Adress
-   SetEntry ("  ",0x0010, 0x0020); // Patient ID
+   SetValEntry ("  ",0x0010, 0x2154); // Telephone   
+   SetValEntry ("  ",0x0010, 0x1040); // Adress
+   SetValEntry ("  ",0x0010, 0x0020); // Patient ID
 
    DocEntry* patientNameHE = GetDocEntry (0x0010, 0x0010);
   
    if ( patientNameHE ) // we replace it by Study Instance UID (why not)
    {
-      std::string studyInstanceUID =  GetEntry (0x0020, 0x000d);
+      std::string studyInstanceUID =  GetEntryValue (0x0020, 0x000d);
       if ( studyInstanceUID != GDCM_UNFOUND )
       {
-         ReplaceOrCreate(studyInstanceUID, 0x0010, 0x0010);
+         InsertValEntry(studyInstanceUID, 0x0010, 0x0010);
       }
       else
       {
-         ReplaceOrCreate("anonymised", 0x0010, 0x0010);
+         InsertValEntry("anonymised", 0x0010, 0x0010);
       }
    }
 
@@ -1281,38 +1343,8 @@ bool File::AnonymizeFile()
    return true;
 }
 
-/**
-  * \brief gets the info from 0020,0037 : Image Orientation Patient
-  * @param iop adress of the (6)float aray to receive values
-  * @return cosines of image orientation patient
-  */
-void 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 = GetEntry(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 )
-      {
-         gdcmVerboseMacro( "Wrong Image Orientation Patient (0020,0037). Less than 6 values were found." );
-      }
-   }
-   //For ACR-NEMA
-   // 0020 0035 DS REL Image Orientation (RET)
-   else if ( (strImOriPat = GetEntry(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 )
-      {
-         gdcmVerboseMacro( "wrong Image Orientation Patient (0020,0035). Less than 6 values were found." );
-      }
-   }
-}
-
+//-----------------------------------------------------------------------------
+// Protected
 /**
  * \brief Initialize a default DICOM File that should contain all the
  *        field require by other reader. DICOM standard does not 
@@ -1332,10 +1364,10 @@ void File::InitializeDefaultFile()
    std::string time = Util::GetCurrentTime();
    std::string uid  = Util::CreateUniqueUID();
    std::string uidMedia = uid;
-   std::string uidClass = uid + ".1";
-   std::string uidInst  = uid + ".10";
-   std::string uidStudy = uid + ".100";
-   std::string uidSerie = uid + ".1000";
+   std::string uidInst  = uid;
+   std::string uidClass = Util::CreateUniqueUID();
+   std::string uidStudy = Util::CreateUniqueUID();
+   std::string uidSerie = Util::CreateUniqueUID();
 
    static DICOM_DEFAULT_VALUE defaultvalue[] = {
     { "146 ",                      0x0002, 0x0000}, // Meta Element Group Length // FIXME: how to recompute ?
@@ -1377,22 +1409,273 @@ void File::InitializeDefaultFile()
    // Special case this is the image (not a string)
    GrPixel = 0x7fe0;
    NumPixel = 0x0010;
-   ReplaceOrCreate(0, 0, GrPixel, NumPixel);
+   InsertBinEntry(0, 0, GrPixel, NumPixel);
 
    // All remaining strings:
    unsigned int i = 0;
    DICOM_DEFAULT_VALUE current = defaultvalue[i];
    while( current.value )
    {
-      ReplaceOrCreate(current.value, current.group, current.elem);
+      InsertValEntry(current.value, current.group, current.elem);
       current = defaultvalue[++i];
    }
 }
 
-
 //-----------------------------------------------------------------------------
 // Private
+/**
+ * \brief Parse pixel data from disk of [multi-]fragment RLE encoding.
+ *        Compute the RLE extra information and store it in \ref RLEInfo
+ *        for later pixel retrieval usage.
+ */
+void File::ComputeRLEInfo()
+{
+   std::string ts = GetTransferSyntax();
+   if ( !Global::GetTS()->IsRLELossless(ts) ) 
+   {
+      return;
+   }
+
+   // Encoded pixel data: for the time being we are only concerned with
+   // Jpeg or RLE Pixel data encodings.
+   // As stated in PS 3.5-2003, section 8.2 p44:
+   // "If sent in Encapsulated Format (i.e. other than the Native Format) the
+   //  value representation OB is used".
+   // Hence we expect an OB value representation. Concerning OB VR,
+   // the section PS 3.5-2003, section A.4.c p 58-59, states:
+   // "For the Value Representations OB and OW, the encoding shall meet the
+   //   following specifications depending on the Data element tag:"
+   //   [...snip...]
+   //    - the first item in the sequence of items before the encoded pixel
+   //      data stream shall be basic offset table item. The basic offset table
+   //      item value, however, is not required to be present"
+   ReadAndSkipEncapsulatedBasicOffsetTable();
+
+   // Encapsulated RLE Compressed Images (see PS 3.5-2003, Annex G)
+   // Loop on the individual frame[s] and store the information
+   // on the RLE fragments in a RLEFramesInfo.
+   // Note: - when only a single frame is present, this is a
+   //         classical image.
+   //       - when more than one frame are present, then we are in 
+   //         the case of a multi-frame image.
+   long frameLength;
+   while ( (frameLength = ReadTagLength(0xfffe, 0xe000)) )
+   { 
+      // Parse the RLE Header and store the corresponding RLE Segment
+      // Offset Table information on fragments of this current Frame.
+      // Note that the fragment pixels themselves are not loaded
+      // (but just skipped).
+      long frameOffset = Fp->tellg();
+
+      uint32_t nbRleSegments = ReadInt32();
+      if ( nbRleSegments > 16 )
+      {
+         // There should be at most 15 segments (refer to RLEFrame class)
+         gdcmVerboseMacro( "Too many segments.");
+      }
+      uint32_t rleSegmentOffsetTable[16];
+      for( int k = 1; k <= 15; k++ )
+      {
+         rleSegmentOffsetTable[k] = ReadInt32();
+      }
+
+      // Deduce from both the RLE Header and the frameLength the
+      // fragment length, and again store this info in a
+      // RLEFramesInfo.
+      long rleSegmentLength[15];
+      // skipping (not reading) RLE Segments
+      if ( nbRleSegments > 1)
+      {
+         for(unsigned int k = 1; k <= nbRleSegments-1; k++)
+         {
+             rleSegmentLength[k] =  rleSegmentOffsetTable[k+1]
+                                  - rleSegmentOffsetTable[k];
+             SkipBytes(rleSegmentLength[k]);
+          }
+       }
+
+       rleSegmentLength[nbRleSegments] = frameLength 
+                                      - rleSegmentOffsetTable[nbRleSegments];
+       SkipBytes(rleSegmentLength[nbRleSegments]);
+
+       // Store the collected info
+       RLEFrame *newFrame = new RLEFrame;
+       newFrame->SetNumberOfFragments(nbRleSegments);
+       for( unsigned int uk = 1; uk <= nbRleSegments; uk++ )
+       {
+          newFrame->SetOffset(uk,frameOffset + rleSegmentOffsetTable[uk]);
+          newFrame->SetLength(uk,rleSegmentLength[uk]);
+       }
+       RLEInfo->AddFrame(newFrame);
+   }
+
+   // Make sure that at the end of the item we encounter a 'Sequence
+   // Delimiter Item':
+   if ( !ReadTag(0xfffe, 0xe0dd) )
+   {
+      gdcmVerboseMacro( "No sequence delimiter item at end of RLE item sequence");
+   }
+}
+
+/**
+ * \brief Parse pixel data from disk of [multi-]fragment Jpeg encoding.
+ *        Compute the jpeg extra information (fragment[s] offset[s] and
+ *        length) and store it[them] in \ref JPEGInfo for later pixel
+ *        retrieval usage.
+ */
+void File::ComputeJPEGFragmentInfo()
+{
+   // If you need to, look for comments of ComputeRLEInfo().
+   std::string ts = GetTransferSyntax();
+   if ( ! Global::GetTS()->IsJPEG(ts) )
+   {
+      return;
+   }
+
+   ReadAndSkipEncapsulatedBasicOffsetTable();
+
+   // Loop on the fragments[s] and store the parsed information in a
+   // JPEGInfo.
+   long fragmentLength;
+   while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) )
+   { 
+      long fragmentOffset = Fp->tellg();
+
+       // Store the collected info
+       JPEGFragment *newFragment = new JPEGFragment;
+       newFragment->SetOffset(fragmentOffset);
+       newFragment->SetLength(fragmentLength);
+       JPEGInfo->AddFragment(newFragment);
+
+       SkipBytes(fragmentLength);
+   }
+
+   // Make sure that at the end of the item we encounter a 'Sequence
+   // Delimiter Item':
+   if ( !ReadTag(0xfffe, 0xe0dd) )
+   {
+      gdcmVerboseMacro( "No sequence delimiter item at end of JPEG item sequence");
+   }
+}
+
+/**
+ * \brief   Assuming the internal file pointer \ref Document::Fp 
+ *          is placed at the beginning of a tag check whether this
+ *          tag is (TestGroup, TestElement).
+ * \warning On success the internal file pointer \ref Document::Fp
+ *          is modified to point after the tag.
+ *          On failure (i.e. when the tag wasn't the expected tag
+ *          (TestGroup, TestElement) the internal file pointer
+ *          \ref Document::Fp is restored to it's original position.
+ * @param   testGroup   The expected group of the tag.
+ * @param   testElement The expected Element of the tag.
+ * @return  True on success, false otherwise.
+ */
+bool File::ReadTag(uint16_t testGroup, uint16_t testElement)
+{
+   long positionOnEntry = Fp->tellg();
+   long currentPosition = Fp->tellg();          // On debugging purposes
+
+   //// Read the Item Tag group and element, and make
+   // sure they are what we expected:
+   uint16_t itemTagGroup;
+   uint16_t itemTagElement;
+   try
+   {
+      itemTagGroup   = ReadInt16();
+      itemTagElement = ReadInt16();
+   }
+   catch ( FormatError e )
+   {
+      //std::cerr << e << std::endl;
+      return false;
+   }
+   if ( itemTagGroup != testGroup || itemTagElement != testElement )
+   {
+      gdcmVerboseMacro( "Wrong Item Tag found:"
+       << "   We should have found tag ("
+       << std::hex << testGroup << "," << testElement << ")" << std::endl
+       << "   but instead we encountered tag ("
+       << std::hex << itemTagGroup << "," << itemTagElement << ")"
+       << "  at address: " << "  0x(" << (unsigned int)currentPosition  << ")" 
+       ) ;
+      Fp->seekg(positionOnEntry, std::ios::beg);
+
+      return false;
+   }
+   return true;
+}
+
+/**
+ * \brief   Assuming the internal file pointer \ref Document::Fp 
+ *          is placed at the beginning of a tag (TestGroup, TestElement),
+ *          read the length associated to the Tag.
+ * \warning On success the internal file pointer \ref Document::Fp
+ *          is modified to point after the tag and it's length.
+ *          On failure (i.e. when the tag wasn't the expected tag
+ *          (TestGroup, TestElement) the internal file pointer
+ *          \ref Document::Fp is restored to it's original position.
+ * @param   testGroup   The expected group of the tag.
+ * @param   testElement The expected Element of the tag.
+ * @return  On success returns the length associated to the tag. On failure
+ *          returns 0.
+ */
+uint32_t File::ReadTagLength(uint16_t testGroup, uint16_t testElement)
+{
+
+   if ( !ReadTag(testGroup, testElement) )
+   {
+      return 0;
+   }
+                                                                                
+   //// Then read the associated Item Length
+   long currentPosition = Fp->tellg();
+   uint32_t itemLength  = ReadInt32();
+   {
+      gdcmVerboseMacro( "Basic Item Length is: "
+        << itemLength << std::endl
+        << "  at address: " << std::hex << (unsigned int)currentPosition);
+   }
+   return itemLength;
+}
+
+/**
+ * \brief When parsing the Pixel Data of an encapsulated file, read
+ *        the basic offset table (when present, and BTW dump it).
+ */
+void File::ReadAndSkipEncapsulatedBasicOffsetTable()
+{
+   //// Read the Basic Offset Table Item Tag length...
+   uint32_t itemLength = ReadTagLength(0xfffe, 0xe000);
+
+   // When present, read the basic offset table itself.
+   // Notes: - since the presence of this basic offset table is optional
+   //          we can't rely on it for the implementation, and we will simply
+   //          trash it's content (when present).
+   //        - still, when present, we could add some further checks on the
+   //          lengths, but we won't bother with such fuses for the time being.
+   if ( itemLength != 0 )
+   {
+      char *basicOffsetTableItemValue = new char[itemLength + 1];
+      Fp->read(basicOffsetTableItemValue, itemLength);
+
+#ifdef GDCM_DEBUG
+      for (unsigned int i=0; i < itemLength; i += 4 )
+      {
+         uint32_t individualLength = str2num( &basicOffsetTableItemValue[i],
+                                              uint32_t);
+         gdcmVerboseMacro( "Read one length: " << 
+                          std::hex << individualLength );
+      }
+#endif //GDCM_DEBUG
+
+      delete[] basicOffsetTableItemValue;
+   }
+}
 
 //-----------------------------------------------------------------------------
+// Print
 
+//-----------------------------------------------------------------------------
 } // end namespace gdcm