Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

gdcmFile.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002                                                                                 
00003   Program:   gdcm
00004   Module:    $RCSfile: gdcmFile.cxx,v $
00005   Language:  C++
00006   Date:      $Date: 2005/02/10 14:23:18 $
00007   Version:   $Revision: 1.222 $
00008                                                                                 
00009   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
00010   l'Image). All rights reserved. See Doc/License.txt or
00011   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
00012                                                                                 
00013      This software is distributed WITHOUT ANY WARRANTY; without even
00014      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00015      PURPOSE.  See the above copyright notices for more information.
00016                                                                                 
00017 =========================================================================*/
00018 
00019 //
00020 // --------------  Remember ! ----------------------------------
00021 //
00022 // Image Position Patient                              (0020,0032):
00023 // If not found (ACR_NEMA) we try Image Position       (0020,0030)
00024 // If not found (ACR-NEMA), we consider Slice Location (0020,1041)
00025 //                                   or Location       (0020,0050) 
00026 //                                   as the Z coordinate, 
00027 // 0. for all the coordinates if nothing is found
00028 //
00029 // ---------------------------------------------------------------
00030 //
00031 #include "gdcmFile.h"
00032 #include "gdcmGlobal.h"
00033 #include "gdcmUtil.h"
00034 #include "gdcmDebug.h"
00035 #include "gdcmTS.h"
00036 #include "gdcmValEntry.h"
00037 #include "gdcmBinEntry.h"
00038 #include "gdcmSeqEntry.h"
00039 #include "gdcmRLEFramesInfo.h"
00040 #include "gdcmJPEGFragmentsInfo.h"
00041 
00042 #include <stdio.h> //sscanf
00043 #include <vector>
00044 
00045 namespace gdcm 
00046 {
00047 //-----------------------------------------------------------------------------
00048 // Constructor / Destructor
00053 File::File( std::string const &filename )
00054      :Document( filename )
00055 {    
00056    RLEInfo  = new RLEFramesInfo;
00057    JPEGInfo = new JPEGFragmentsInfo;
00058 
00059    // for some ACR-NEMA images GrPixel, NumPixel is *not* 7fe0,0010
00060    // We may encounter the 'RETired' (0x0028, 0x0200) tag
00061    // (Image Location") . This entry contains the number of
00062    // the group that contains the pixel data (hence the "Pixel Data"
00063    // is found by indirection through the "Image Location").
00064    // Inside the group pointed by "Image Location" the searched element
00065    // is conventionally the element 0x0010 (when the norm is respected).
00066    // When the "Image Location" is missing we default to group 0x7fe0.
00067    // Note: this IS the right place for the code
00068  
00069    // Image Location
00070    const std::string &imgLocation = GetEntryValue(0x0028, 0x0200);
00071    if ( imgLocation == GDCM_UNFOUND )
00072    {
00073       // default value
00074       GrPixel = 0x7fe0;
00075    }
00076    else
00077    {
00078       GrPixel = (uint16_t) atoi( imgLocation.c_str() );
00079    }   
00080 
00081    // sometimes Image Location value doesn't follow
00082    // the supposed processor endianness.
00083    // see gdcmData/cr172241.dcm
00084    if ( GrPixel == 0xe07f )
00085    {
00086       GrPixel = 0x7fe0;
00087    }
00088 
00089    if ( GrPixel != 0x7fe0 )
00090    {
00091       // This is a kludge for old dirty Philips imager.
00092       NumPixel = 0x1010;
00093    }
00094    else
00095    {
00096       NumPixel = 0x0010;
00097    }
00098 
00099    // Now, we know GrPixel and NumPixel.
00100    // Let's create a VirtualDictEntry to allow a further VR modification
00101    // and force VR to match with BitsAllocated.
00102    DocEntry *entry = GetDocEntry(GrPixel, NumPixel); 
00103    if ( entry != 0 )
00104    {
00105       // Compute the RLE or JPEG info
00106       OpenFile();
00107       std::string ts = GetTransferSyntax();
00108       Fp->seekg( entry->GetOffset(), std::ios::beg );
00109       if ( Global::GetTS()->IsRLELossless(ts) ) 
00110          ComputeRLEInfo();
00111       else if ( Global::GetTS()->IsJPEG(ts) )
00112          ComputeJPEGFragmentInfo();
00113       CloseFile();
00114 
00115       // Create a new BinEntry to change the the DictEntry
00116       // The changed DictEntry will have 
00117       // - a correct PixelVR OB or OW)
00118       // - a VM to "PXL"
00119       // - the name to "Pixel Data"
00120       BinEntry *oldEntry = dynamic_cast<BinEntry *>(entry);
00121       if(oldEntry)
00122       {
00123          std::string PixelVR;
00124          // 8 bits allocated is a 'O Bytes' , as well as 24 (old ACR-NEMA RGB)
00125          // more than 8 (i.e 12, 16) is a 'O Words'
00126          if ( GetBitsAllocated() == 8 || GetBitsAllocated() == 24 ) 
00127             PixelVR = "OB";
00128          else
00129             PixelVR = "OW";
00130 
00131          // Change only made if usefull
00132          if( PixelVR != oldEntry->GetVR() )
00133          {
00134             DictEntry* newDict = NewVirtualDictEntry(GrPixel,NumPixel,
00135                                                      PixelVR,"1","Pixel Data");
00136 
00137             BinEntry *newEntry = new BinEntry(newDict);
00138             newEntry->Copy(entry);
00139             newEntry->SetBinArea(oldEntry->GetBinArea(),oldEntry->IsSelfArea());
00140             oldEntry->SetSelfArea(false);
00141 
00142             RemoveEntry(oldEntry);
00143             AddEntry(newEntry);
00144          }
00145       }
00146    }
00147 }
00148 
00152 File::File():
00153    Document()
00154 {
00155    RLEInfo  = new RLEFramesInfo;
00156    JPEGInfo = new JPEGFragmentsInfo;
00157    InitializeDefaultFile();
00158 }
00159 
00163 File::~File ()
00164 {
00165    if( RLEInfo )
00166       delete RLEInfo;
00167    if( JPEGInfo )
00168       delete JPEGInfo;
00169 }
00170 
00171 //-----------------------------------------------------------------------------
00172 // Public
00181 bool File::IsReadable()
00182 {
00183    if( !Document::IsReadable() )
00184    {
00185       return false;
00186    }
00187 
00188    const std::string &res = GetEntryValue(0x0028, 0x0005);
00189    if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 )
00190    {
00191       return false; // Image Dimensions
00192    }
00193    if ( !GetDocEntry(0x0028, 0x0100) )
00194    {
00195       return false; // "Bits Allocated"
00196    }
00197    if ( !GetDocEntry(0x0028, 0x0101) )
00198    {
00199       return false; // "Bits Stored"
00200    }
00201    if ( !GetDocEntry(0x0028, 0x0102) )
00202    {
00203       return false; // "High Bit"
00204    }
00205    if ( !GetDocEntry(0x0028, 0x0103) )
00206    {
00207       return false; // "Pixel Representation" i.e. 'Sign'
00208    }
00209 
00210    return true;
00211 }
00212 
00217 int File::GetImageNumber()
00218 {
00219    // The function i atoi() takes the address of an area of memory as
00220    // parameter and converts the string stored at that location to an integer
00221    // using the external decimal to internal binary conversion rules. This may
00222    // be preferable to sscanf() since atoi() is a much smaller, simpler and
00223    // faster function. sscanf() can do all possible conversions whereas
00224    // atoi() can only do single decimal integer conversions.
00225    //0020 0013 IS REL Image Number
00226    std::string strImNumber = GetEntryValue(0x0020,0x0013);
00227    if ( strImNumber != GDCM_UNFOUND )
00228    {
00229       return atoi( strImNumber.c_str() );
00230    }
00231    return 0;   //Hopeless
00232 }
00233 
00238 ModalityType File::GetModality()
00239 {
00240    // 0008 0060 CS ID Modality
00241    std::string strModality = GetEntryValue(0x0008,0x0060);
00242    if ( strModality != GDCM_UNFOUND )
00243    {
00244            if ( strModality.find("AU") < strModality.length()) return AU;
00245       else if ( strModality.find("AS") < strModality.length()) return AS;
00246       else if ( strModality.find("BI") < strModality.length()) return BI;
00247       else if ( strModality.find("CF") < strModality.length()) return CF;
00248       else if ( strModality.find("CP") < strModality.length()) return CP;
00249       else if ( strModality.find("CR") < strModality.length()) return CR;
00250       else if ( strModality.find("CT") < strModality.length()) return CT;
00251       else if ( strModality.find("CS") < strModality.length()) return CS;
00252       else if ( strModality.find("DD") < strModality.length()) return DD;
00253       else if ( strModality.find("DF") < strModality.length()) return DF;
00254       else if ( strModality.find("DG") < strModality.length()) return DG;
00255       else if ( strModality.find("DM") < strModality.length()) return DM;
00256       else if ( strModality.find("DS") < strModality.length()) return DS;
00257       else if ( strModality.find("DX") < strModality.length()) return DX;
00258       else if ( strModality.find("ECG") < strModality.length()) return ECG;
00259       else if ( strModality.find("EPS") < strModality.length()) return EPS;
00260       else if ( strModality.find("FA") < strModality.length()) return FA;
00261       else if ( strModality.find("FS") < strModality.length()) return FS;
00262       else if ( strModality.find("HC") < strModality.length()) return HC;
00263       else if ( strModality.find("HD") < strModality.length()) return HD;
00264       else if ( strModality.find("LP") < strModality.length()) return LP;
00265       else if ( strModality.find("LS") < strModality.length()) return LS;
00266       else if ( strModality.find("MA") < strModality.length()) return MA;
00267       else if ( strModality.find("MR") < strModality.length()) return MR;
00268       else if ( strModality.find("NM") < strModality.length()) return NM;
00269       else if ( strModality.find("OT") < strModality.length()) return OT;
00270       else if ( strModality.find("PT") < strModality.length()) return PT;
00271       else if ( strModality.find("RF") < strModality.length()) return RF;
00272       else if ( strModality.find("RG") < strModality.length()) return RG;
00273       else if ( strModality.find("RTDOSE")   < strModality.length()) return RTDOSE;
00274       else if ( strModality.find("RTIMAGE")  < strModality.length()) return RTIMAGE;
00275       else if ( strModality.find("RTPLAN")   < strModality.length()) return RTPLAN;
00276       else if ( strModality.find("RTSTRUCT") < strModality.length()) return RTSTRUCT;
00277       else if ( strModality.find("SM") < strModality.length()) return SM;
00278       else if ( strModality.find("ST") < strModality.length()) return ST;
00279       else if ( strModality.find("TG") < strModality.length()) return TG;
00280       else if ( strModality.find("US") < strModality.length()) return US;
00281       else if ( strModality.find("VF") < strModality.length()) return VF;
00282       else if ( strModality.find("XA") < strModality.length()) return XA;
00283       else if ( strModality.find("XC") < strModality.length()) return XC;
00284 
00285       else
00286       {
00289          return Unknow;
00290       }
00291    }
00292 
00293    return Unknow;
00294 }
00295 
00301 int File::GetXSize()
00302 {
00303    const std::string &strSize = GetEntryValue(0x0028,0x0011);
00304    if ( strSize == GDCM_UNFOUND )
00305    {
00306       return 0;
00307    }
00308 
00309    return atoi( strSize.c_str() );
00310 }
00311 
00318 int File::GetYSize()
00319 {
00320    const std::string &strSize = GetEntryValue(0x0028,0x0010);
00321    if ( strSize != GDCM_UNFOUND )
00322    {
00323       return atoi( strSize.c_str() );
00324    }
00325    if ( IsDicomV3() )
00326    {
00327       return 0;
00328    }
00329 
00330    // The Rows (0028,0010) entry was optional for ACR/NEMA. It might
00331    // hence be a signal (1D image). So we default to 1:
00332    return 1;
00333 }
00334 
00343 int File::GetZSize()
00344 {
00345    // Both  DicomV3 and ACR/Nema consider the "Number of Frames"
00346    // as the third dimension.
00347    const std::string &strSize = GetEntryValue(0x0028,0x0008);
00348    if ( strSize != GDCM_UNFOUND )
00349    {
00350       return atoi( strSize.c_str() );
00351    }
00352 
00353    // We then consider the "Planes" entry as the third dimension 
00354    const std::string &strSize2 = GetEntryValue(0x0028,0x0012);
00355    if ( strSize2 != GDCM_UNFOUND )
00356    {
00357       return atoi( strSize2.c_str() );
00358    }
00359 
00360    return 1;
00361 }
00362 
00368 float File::GetXSpacing()
00369 {
00370    float xspacing = 1.0;
00371    float yspacing = 1.0;
00372    const std::string &strSpacing = GetEntryValue(0x0028,0x0030);
00373 
00374    if( strSpacing == GDCM_UNFOUND )
00375    {
00376       gdcmWarningMacro( "Unfound Pixel Spacing (0028,0030)" );
00377       return 1.;
00378    }
00379 
00380    int nbValues;
00381    if( ( nbValues = sscanf( strSpacing.c_str(), 
00382          "%f\\%f", &yspacing, &xspacing)) != 2 )
00383    {
00384       // if no values, xspacing is set to 1.0
00385       if( nbValues == 0 )
00386          xspacing = 1.0;
00387       // if single value is found, xspacing is defaulted to yspacing
00388       if( nbValues == 1 )
00389          xspacing = yspacing;
00390 
00391       if ( xspacing == 0.0 )
00392          xspacing = 1.0;
00393 
00394       return xspacing;
00395 
00396    }
00397 
00398    // to avoid troubles with David Clunie's-like images
00399    if ( xspacing == 0. && yspacing == 0.)
00400       return 1.;
00401 
00402    if ( xspacing == 0.)
00403    {
00404       gdcmWarningMacro("gdcmData/CT-MONO2-8-abdo.dcm problem");
00405       // seems to be a bug in the header ...
00406       nbValues = sscanf( strSpacing.c_str(), "%f\\0\\%f", &yspacing, &xspacing);
00407       gdcmAssertMacro( nbValues == 2 );
00408    }
00409 
00410    return xspacing;
00411 }
00412 
00418 float File::GetYSpacing()
00419 {
00420    float yspacing = 1.;
00421    std::string strSpacing = GetEntryValue(0x0028,0x0030);
00422   
00423    if ( strSpacing == GDCM_UNFOUND )
00424    {
00425       gdcmWarningMacro("Unfound Pixel Spacing (0028,0030)");
00426       return 1.;
00427     }
00428 
00429    // if sscanf cannot read any float value, it won't affect yspacing
00430    int nbValues = sscanf( strSpacing.c_str(), "%f", &yspacing);
00431 
00432    // if no values, xspacing is set to 1.0
00433    if( nbValues == 0 )
00434       yspacing = 1.0;
00435 
00436    if ( yspacing == 0.0 )
00437       yspacing = 1.0;
00438 
00439    return yspacing;
00440 } 
00441 
00448 float File::GetZSpacing()
00449 {
00450    // Spacing Between Slices : distance entre le milieu de chaque coupe
00451    // Les coupes peuvent etre :
00452    //   jointives     (Spacing between Slices = Slice Thickness)
00453    //   chevauchantes (Spacing between Slices < Slice Thickness)
00454    //   disjointes    (Spacing between Slices > Slice Thickness)
00455    // Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal
00456    //   ca interesse le physicien de l'IRM, pas le visualisateur de volumes ...
00457    //   Si le Spacing Between Slices est Missing, 
00458    //   on suppose que les coupes sont jointives
00459    
00460    const std::string &strSpacingBSlices = GetEntryValue(0x0018,0x0088);
00461 
00462    if ( strSpacingBSlices == GDCM_UNFOUND )
00463    {
00464       gdcmWarningMacro("Unfound Spacing Between Slices (0018,0088)");
00465       const std::string &strSliceThickness = GetEntryValue(0x0018,0x0050);       
00466       if ( strSliceThickness == GDCM_UNFOUND )
00467       {
00468          gdcmWarningMacro("Unfound Slice Thickness (0018,0050)");
00469          return 1.;
00470       }
00471       else
00472       {
00473          // if no 'Spacing Between Slices' is found, 
00474          // we assume slices join together
00475          // (no overlapping, no interslice gap)
00476          // if they don't, we're fucked up
00477          return (float)atof( strSliceThickness.c_str() );
00478       }
00479    }
00480    //else
00481    return (float)atof( strSpacingBSlices.c_str() );
00482 }
00483 
00490 float File::GetXOrigin()
00491 {
00492    float xImPos, yImPos, zImPos;  
00493    std::string strImPos = GetEntryValue(0x0020,0x0032);
00494 
00495    if ( strImPos == GDCM_UNFOUND )
00496    {
00497       gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
00498       strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images
00499       if ( strImPos == GDCM_UNFOUND )
00500       {
00501          gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
00502          return 0.;
00503       }
00504    }
00505 
00506    if( sscanf( strImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3 )
00507    {
00508       return 0.;
00509    }
00510 
00511    return xImPos;
00512 }
00513 
00520 float File::GetYOrigin()
00521 {
00522    float xImPos, yImPos, zImPos;
00523    std::string strImPos = GetEntryValue(0x0020,0x0032);
00524 
00525    if ( strImPos == GDCM_UNFOUND)
00526    {
00527       gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
00528       strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images
00529       if ( strImPos == GDCM_UNFOUND )
00530       {
00531          gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
00532          return 0.;
00533       }  
00534    }
00535 
00536    if( sscanf( strImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3 )
00537    {
00538       return 0.;
00539    }
00540 
00541    return yImPos;
00542 }
00543 
00552 float File::GetZOrigin()
00553 {
00554    float xImPos, yImPos, zImPos; 
00555    std::string strImPos = GetEntryValue(0x0020,0x0032);
00556 
00557    if ( strImPos != GDCM_UNFOUND )
00558    {
00559       if( sscanf( strImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3)
00560       {
00561          gdcmWarningMacro( "Wrong Image Position Patient (0020,0032)");
00562          return 0.;  // bug in the element 0x0020,0x0032
00563       }
00564       else
00565       {
00566          return zImPos;
00567       }
00568    }
00569 
00570    strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images
00571    if ( strImPos != GDCM_UNFOUND )
00572    {
00573       if( sscanf( strImPos.c_str(), 
00574           "%f\\%f\\%f", &xImPos, &yImPos, &zImPos ) != 3 )
00575       {
00576          gdcmWarningMacro( "Wrong Image Position (RET) (0020,0030)");
00577          return 0.;  // bug in the element 0x0020,0x0032
00578       }
00579       else
00580       {
00581          return zImPos;
00582       }
00583    }
00584 
00585    std::string strSliceLocation = GetEntryValue(0x0020,0x1041); // for *very* old ACR-NEMA images
00586    if ( strSliceLocation != GDCM_UNFOUND )
00587    {
00588       if( sscanf( strSliceLocation.c_str(), "%f", &zImPos) != 1)
00589       {
00590          gdcmWarningMacro( "Wrong Slice Location (0020,1041)");
00591          return 0.;  // bug in the element 0x0020,0x1041
00592       }
00593       else
00594       {
00595          return zImPos;
00596       }
00597    }
00598    gdcmWarningMacro( "Unfound Slice Location (0020,1041)");
00599 
00600    std::string strLocation = GetEntryValue(0x0020,0x0050);
00601    if ( strLocation != GDCM_UNFOUND )
00602    {
00603       if( sscanf( strLocation.c_str(), "%f", &zImPos) != 1)
00604       {
00605          gdcmWarningMacro( "Wrong Location (0020,0050)");
00606          return 0.;  // bug in the element 0x0020,0x0050
00607       }
00608       else
00609       {
00610          return zImPos;
00611       }
00612    }
00613    gdcmWarningMacro( "Unfound Location (0020,0050)");  
00614 
00615    return 0.; // Hopeless
00616 }
00617 
00624 void File::GetImageOrientationPatient( float iop[6] )
00625 {
00626    std::string strImOriPat;
00627    //iop is supposed to be float[6]
00628    iop[0] = iop[1] = iop[2] = iop[3] = iop[4] = iop[5] = 0.;
00629 
00630    // 0020 0037 DS REL Image Orientation (Patient)
00631    if ( (strImOriPat = GetEntryValue(0x0020,0x0037)) != GDCM_UNFOUND )
00632    {
00633       if( sscanf( strImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", 
00634           &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 )
00635       {
00636          gdcmWarningMacro( "Wrong Image Orientation Patient (0020,0037). Less than 6 values were found." );
00637       }
00638    }
00639    //For ACR-NEMA
00640    // 0020 0035 DS REL Image Orientation (RET)
00641    else if ( (strImOriPat = GetEntryValue(0x0020,0x0035)) != GDCM_UNFOUND )
00642    {
00643       if( sscanf( strImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", 
00644           &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 )
00645       {
00646          gdcmWarningMacro( "wrong Image Orientation Patient (0020,0035). Less than 6 values were found." );
00647       }
00648    }
00649 }
00650 
00657 int File::GetBitsStored()
00658 {
00659    std::string strSize = GetEntryValue( 0x0028, 0x0101 );
00660    if ( strSize == GDCM_UNFOUND )
00661    {
00662       gdcmWarningMacro("(0028,0101) is supposed to be mandatory");
00663       return 0;  // It's supposed to be mandatory
00664                  // the caller will have to check
00665    }
00666    return atoi( strSize.c_str() );
00667 }
00668 
00675 int File::GetBitsAllocated()
00676 {
00677    std::string strSize = GetEntryValue(0x0028,0x0100);
00678    if ( strSize == GDCM_UNFOUND )
00679    {
00680       gdcmWarningMacro( "(0028,0100) is supposed to be mandatory");
00681       return 0; // It's supposed to be mandatory
00682                 // the caller will have to check
00683    }
00684    return atoi( strSize.c_str() );
00685 }
00686 
00693 int File::GetHighBitPosition()
00694 {
00695    std::string strSize = GetEntryValue( 0x0028, 0x0102 );
00696    if ( strSize == GDCM_UNFOUND )
00697    {
00698       gdcmWarningMacro( "(0028,0102) is supposed to be mandatory");
00699       return 0;
00700    }
00701    return atoi( strSize.c_str() );
00702 }
00703 
00710 int File::GetSamplesPerPixel()
00711 {
00712    const std::string &strSize = GetEntryValue(0x0028,0x0002);
00713    if ( strSize == GDCM_UNFOUND )
00714    {
00715       gdcmWarningMacro( "(0028,0002) is supposed to be mandatory");
00716       return 1; // Well, it's supposed to be mandatory ...
00717                 // but sometimes it's missing : *we* assume Gray pixels
00718    }
00719    return atoi( strSize.c_str() );
00720 }
00721 
00727 int File::GetPlanarConfiguration()
00728 {
00729    std::string strSize = GetEntryValue(0x0028,0x0006);
00730    if ( strSize == GDCM_UNFOUND )
00731    {
00732       gdcmWarningMacro( "Not found : Planar Configuration (0028,0006)");
00733       return 0;
00734    }
00735    return atoi( strSize.c_str() );
00736 }
00737 
00743 int File::GetPixelSize()
00744 {
00745    // 0028 0100 US IMG Bits Allocated
00746    // (in order no to be messed up by old RGB images)
00747    //   if (File::GetEntryValue(0x0028,0x0100) == "24")
00748    //      return 3;
00749 
00750    std::string pixelType = GetPixelType();
00751    if ( pixelType ==  "8U" || pixelType == "8S" )
00752    {
00753       return 1;
00754    }
00755    if ( pixelType == "16U" || pixelType == "16S")
00756    {
00757       return 2;
00758    }
00759    if ( pixelType == "32U" || pixelType == "32S")
00760    {
00761       return 4;
00762    }
00763    if ( pixelType == "FD" )
00764    {
00765       return 8;
00766    }
00767    gdcmWarningMacro( "Unknown pixel type");
00768    return 0;
00769 }
00770 
00785 std::string File::GetPixelType()
00786 {
00787    std::string bitsAlloc = GetEntryValue(0x0028, 0x0100); // Bits Allocated
00788    if ( bitsAlloc == GDCM_UNFOUND )
00789    {
00790       gdcmWarningMacro( "Missing  Bits Allocated (0028,0100)");
00791       bitsAlloc = "16"; // default and arbitrary value, not to polute the output
00792    }
00793 
00794    if ( bitsAlloc == "64" )
00795    {
00796       return "FD";
00797    }
00798    else if ( bitsAlloc == "12" )
00799    {
00800       // It will be unpacked
00801       bitsAlloc = "16";
00802    }
00803    else if ( bitsAlloc == "24" )
00804    {
00805       // (in order no to be messed up
00806       bitsAlloc = "8";  // by old RGB images)
00807    }
00808 
00809    std::string sign = GetEntryValue(0x0028, 0x0103);//"Pixel Representation"
00810 
00811    if (sign == GDCM_UNFOUND )
00812    {
00813       gdcmWarningMacro( "Missing Pixel Representation (0028,0103)");
00814       sign = "U"; // default and arbitrary value, not to polute the output
00815    }
00816    else if ( sign == "0" )
00817    {
00818       sign = "U";
00819    }
00820    else
00821    {
00822       sign = "S";
00823    }
00824    return bitsAlloc + sign;
00825 }
00826 
00833 bool File::IsSignedPixelData()
00834 {
00835    std::string strSize = GetEntryValue( 0x0028, 0x0103 );
00836    if ( strSize == GDCM_UNFOUND )
00837    {
00838       gdcmWarningMacro( "(0028,0103) is supposed to be mandatory");
00839       return false;
00840    }
00841    int sign = atoi( strSize.c_str() );
00842    if ( sign == 0 ) 
00843    {
00844       return false;
00845    }
00846    return true;
00847 }
00848 
00854 bool File::IsMonochrome()
00855 {
00856    const std::string &PhotometricInterp = GetEntryValue( 0x0028, 0x0004 );
00857    if (  Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1")
00858       || Util::DicomStringEqual(PhotometricInterp, "MONOCHROME2") )
00859    {
00860       return true;
00861    }
00862    if ( PhotometricInterp == GDCM_UNFOUND )
00863    {
00864       gdcmWarningMacro( "Not found : Photometric Interpretation (0028,0004)");
00865    }
00866    return false;
00867 }
00868 
00874 bool File::IsPaletteColor()
00875 {
00876    std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 );
00877    if (   PhotometricInterp == "PALETTE COLOR " )
00878    {
00879       return true;
00880    }
00881    if ( PhotometricInterp == GDCM_UNFOUND )
00882    {
00883       gdcmWarningMacro( "Not found : Palette color (0028,0004)");
00884    }
00885    return false;
00886 }
00887 
00893 bool File::IsYBRFull()
00894 {
00895    std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 );
00896    if (   PhotometricInterp == "YBR_FULL" )
00897    {
00898       return true;
00899    }
00900    if ( PhotometricInterp == GDCM_UNFOUND )
00901    {
00902       gdcmWarningMacro( "Not found : YBR Full (0028,0004)");
00903    }
00904    return false;
00905 }
00906 
00915 bool File::HasLUT()
00916 {
00917    // Check the presence of the LUT Descriptors, and LUT Tables    
00918    // LutDescriptorRed    
00919    if ( !GetDocEntry(0x0028,0x1101) )
00920    {
00921       return false;
00922    }
00923    // LutDescriptorGreen 
00924    if ( !GetDocEntry(0x0028,0x1102) )
00925    {
00926       return false;
00927    }
00928    // LutDescriptorBlue 
00929    if ( !GetDocEntry(0x0028,0x1103) )
00930    {
00931       return false;
00932    }
00933    // Red Palette Color Lookup Table Data
00934    if ( !GetDocEntry(0x0028,0x1201) )
00935    {
00936       return false;
00937    }
00938    // Green Palette Color Lookup Table Data       
00939    if ( !GetDocEntry(0x0028,0x1202) )
00940    {
00941       return false;
00942    }
00943    // Blue Palette Color Lookup Table Data      
00944    if ( !GetDocEntry(0x0028,0x1203) )
00945    {
00946       return false;
00947    }
00948 
00949    // FIXME : (0x0028,0x3006) : LUT Data (CTX dependent)
00950    //         NOT taken into account, but we don't know how to use it ...   
00951    return true;
00952 }
00953 
00961 int File::GetLUTNbits()
00962 {
00963    std::vector<std::string> tokens;
00964    int lutNbits;
00965 
00966    //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red
00967    //                                = Lookup Table Desc-Blue
00968    // Consistency already checked in GetLUTLength
00969    std::string lutDescription = GetEntryValue(0x0028,0x1101);
00970    if ( lutDescription == GDCM_UNFOUND )
00971    {
00972       return 0;
00973    }
00974 
00975    tokens.clear(); // clean any previous value
00976    Util::Tokenize ( lutDescription, tokens, "\\" );
00977    //LutLength=atoi(tokens[0].c_str());
00978    //LutDepth=atoi(tokens[1].c_str());
00979 
00980    lutNbits = atoi( tokens[2].c_str() );
00981    tokens.clear();
00982 
00983    return lutNbits;
00984 }
00985 
00990 float File::GetRescaleIntercept()
00991 {
00992    float resInter = 0.;
00994    const std::string &strRescInter = GetEntryValue(0x0028,0x1052);
00995    if ( strRescInter != GDCM_UNFOUND )
00996    {
00997       if( sscanf( strRescInter.c_str(), "%f", &resInter) != 1 )
00998       {
00999          // bug in the element 0x0028,0x1052
01000          gdcmWarningMacro( "Rescale Intercept (0028,1052) is empty." );
01001       }
01002    }
01003 
01004    return resInter;
01005 }
01006 
01011 float File::GetRescaleSlope()
01012 {
01013    float resSlope = 1.;
01014    //0028 1053 DS IMG Rescale Slope
01015    std::string strRescSlope = GetEntryValue(0x0028,0x1053);
01016    if ( strRescSlope != GDCM_UNFOUND )
01017    {
01018       if( sscanf( strRescSlope.c_str(), "%f", &resSlope) != 1)
01019       {
01020          // bug in the element 0x0028,0x1053
01021          gdcmWarningMacro( "Rescale Slope (0028,1053) is empty.");
01022       }
01023    }
01024 
01025    return resSlope;
01026 }
01027 
01035 int File::GetNumberOfScalarComponents()
01036 {
01037    if ( GetSamplesPerPixel() == 3 )
01038    {
01039       return 3;
01040    }
01041       
01042    // 0028 0100 US IMG Bits Allocated
01043    // (in order no to be messed up by old RGB images)
01044    if ( GetEntryValue(0x0028,0x0100) == "24" )
01045    {
01046       return 3;
01047    }
01048        
01049    std::string strPhotometricInterpretation = GetEntryValue(0x0028,0x0004);
01050 
01051    if ( ( strPhotometricInterpretation == "PALETTE COLOR ") )
01052    {
01053       if ( HasLUT() )// PALETTE COLOR is NOT enough
01054       {
01055          return 3;
01056       }
01057       else
01058       {
01059          return 1;
01060       }
01061    }
01062 
01063    // beware of trailing space at end of string      
01064    // DICOM tags are never of odd length
01065    if ( strPhotometricInterpretation == GDCM_UNFOUND   || 
01066         Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME1") ||
01067         Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME2") )
01068    {
01069       return 1;
01070    }
01071    else
01072    {
01073       // we assume that *all* kinds of YBR are dealt with
01074       return 3;
01075    }
01076 }
01077 
01085 int File::GetNumberOfScalarComponentsRaw()
01086 {
01087    // 0028 0100 US IMG Bits Allocated
01088    // (in order no to be messed up by old RGB images)
01089    if ( File::GetEntryValue(0x0028,0x0100) == "24" )
01090    {
01091       return 3;
01092    }
01093 
01094    // we assume that *all* kinds of YBR are dealt with
01095    return GetSamplesPerPixel();
01096 }
01097 
01103 size_t File::GetPixelOffset()
01104 {
01105    DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel);
01106    if ( pxlElement )
01107    {
01108       return pxlElement->GetOffset();
01109    }
01110    else
01111    {
01112       gdcmDebugMacro( "Big trouble : Pixel Element ("
01113                       << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" );
01114       return 0;
01115    }
01116 }
01117 
01125 size_t File::GetPixelAreaLength()
01126 {
01127    DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel);
01128    if ( pxlElement )
01129    {
01130       return pxlElement->GetLength();
01131    }
01132    else
01133    {
01134       gdcmDebugMacro( "Big trouble : Pixel Element ("
01135                       << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" );
01136       return 0;
01137    }
01138 }
01139 
01144 void File::AddAnonymizeElement (uint16_t group, uint16_t elem, 
01145                                 std::string const &value) 
01146 
01147 { 
01148    Element el;
01149    el.Group = group;
01150    el.Elem  = elem;
01151    el.Value = value;
01152    AnonymizeList.push_back(el); 
01153 }
01154 
01159 void File::AnonymizeNoLoad()
01160 {
01161    std::fstream *fp = new std::fstream(Filename.c_str(), 
01162                               std::ios::in | std::ios::out | std::ios::binary);
01163  
01164    // TODO : FIXME
01165    // how to white out disk space if longer than 50 ?
01166    
01167    
01168    gdcm::DocEntry *d;
01169    uint32_t offset;
01170    uint32_t lgth;
01171    uint32_t valLgth;
01172    std::string *spaces;
01173    for (ListElements::iterator it = AnonymizeList.begin();  
01174                                it != AnonymizeList.end();
01175                              ++it)
01176    { 
01177       d = GetDocEntry( (*it).Group, (*it).Elem);
01178 
01179       if ( d == NULL)
01180          continue;
01181 
01182       if ( dynamic_cast<BinEntry *>(d)
01183         || dynamic_cast<SeqEntry *>(d) )
01184          continue;
01185 
01186       offset = d->GetOffset();
01187       lgth =   d->GetLength();
01188       if (valLgth < lgth)
01189       {
01190          spaces = new std::string( lgth-valLgth, ' ');
01191          (*it).Value = (*it).Value + *spaces;
01192          delete spaces;
01193       }
01194       fp->seekp( offset, std::ios::beg );
01195       fp->write( (*it).Value.c_str(), lgth );
01196      
01197    }
01198    fp->close();
01199    delete fp;
01200 }
01201 
01206 bool File::AnonymizeFile()
01207 {
01208    // If Anonymisation list is empty, let's perform some basic anonymization
01209    if ( AnonymizeList.begin() == AnonymizeList.end() )
01210    {
01211       // If exist, replace by spaces
01212       SetValEntry ("  ",0x0010, 0x2154); // Telephone   
01213       SetValEntry ("  ",0x0010, 0x1040); // Adress
01214       SetValEntry ("  ",0x0010, 0x0020); // Patient ID
01215 
01216       DocEntry* patientNameHE = GetDocEntry (0x0010, 0x0010);
01217   
01218       if ( patientNameHE ) // we replace it by Study Instance UID (why not ?)
01219       {
01220          std::string studyInstanceUID =  GetEntryValue (0x0020, 0x000d);
01221          if ( studyInstanceUID != GDCM_UNFOUND )
01222          {
01223             SetValEntry(studyInstanceUID, 0x0010, 0x0010);
01224          }
01225          else
01226          {
01227             SetValEntry("anonymised", 0x0010, 0x0010);
01228          }
01229       }
01230    }
01231    else
01232    {
01233       gdcm::DocEntry *d;
01234       for (ListElements::iterator it = AnonymizeList.begin();  
01235                                   it != AnonymizeList.end();
01236                                 ++it)
01237       {  
01238          d = GetDocEntry( (*it).Group, (*it).Elem);
01239 
01240          if ( d == NULL)
01241             continue;
01242 
01243          if ( dynamic_cast<BinEntry *>(d)
01244            || dynamic_cast<SeqEntry *>(d) )
01245             continue;
01246 
01247          SetValEntry ((*it).Value, (*it).Group, (*it).Elem);
01248       }
01249 }
01250 
01251   // In order to make definitively impossible any further identification
01252   // remove or replace all the stuff that contains a Date
01253 
01254 //0008 0012 DA ID Instance Creation Date
01255 //0008 0020 DA ID Study Date
01256 //0008 0021 DA ID Series Date
01257 //0008 0022 DA ID Acquisition Date
01258 //0008 0023 DA ID Content Date
01259 //0008 0024 DA ID Overlay Date
01260 //0008 0025 DA ID Curve Date
01261 //0008 002a DT ID Acquisition Datetime
01262 //0018 9074 DT ACQ Frame Acquisition Datetime
01263 //0018 9151 DT ACQ Frame Reference Datetime
01264 //0018 a002 DT ACQ Contribution Date Time
01265 //0020 3403 SH REL Modified Image Date (RET)
01266 //0032 0032 DA SDY Study Verified Date
01267 //0032 0034 DA SDY Study Read Date
01268 //0032 1000 DA SDY Scheduled Study Start Date
01269 //0032 1010 DA SDY Scheduled Study Stop Date
01270 //0032 1040 DA SDY Study Arrival Date
01271 //0032 1050 DA SDY Study Completion Date
01272 //0038 001a DA VIS Scheduled Admission Date
01273 //0038 001c DA VIS Scheduled Discharge Date
01274 //0038 0020 DA VIS Admitting Date
01275 //0038 0030 DA VIS Discharge Date
01276 //0040 0002 DA PRC Scheduled Procedure Step Start Date
01277 //0040 0004 DA PRC Scheduled Procedure Step End Date
01278 //0040 0244 DA PRC Performed Procedure Step Start Date
01279 //0040 0250 DA PRC Performed Procedure Step End Date
01280 //0040 2004 DA PRC Issue Date of Imaging Service Request
01281 //0040 4005 DT PRC Scheduled Procedure Step Start Date and Time
01282 //0040 4011 DT PRC Expected Completion Date and Time
01283 //0040 a030 DT PRC Verification Date Time
01284 //0040 a032 DT PRC Observation Date Time
01285 //0040 a120 DT PRC DateTime
01286 //0040 a121 DA PRC Date
01287 //0040 a13a DT PRC Referenced Datetime
01288 //0070 0082 DA ??? Presentation Creation Date
01289 //0100 0420 DT ??? SOP Autorization Date and Time
01290 //0400 0105 DT ??? Digital Signature DateTime
01291 //2100 0040 DA PJ Creation Date
01292 //3006 0008 DA SSET Structure Set Date
01293 //3008 0024 DA ??? Treatment Control Point Date
01294 //3008 0054 DA ??? First Treatment Date
01295 //3008 0056 DA ??? Most Recent Treatment Date
01296 //3008 0162 DA ??? Safe Position Exit Date
01297 //3008 0166 DA ??? Safe Position Return Date
01298 //3008 0250 DA ??? Treatment Date
01299 //300a 0006 DA RT RT Plan Date
01300 //300a 022c DA RT Air Kerma Rate Reference Date
01301 //300e 0004 DA RT Review Date
01302 
01303    return true;
01304 }
01305 
01314 bool File::Write(std::string fileName, FileType filetype)
01315 {
01316    std::ofstream *fp = new std::ofstream(fileName.c_str(), 
01317                                          std::ios::out | std::ios::binary);
01318    if (*fp == NULL)
01319    {
01320       gdcmWarningMacro("Failed to open (write) File: " << fileName.c_str());
01321       return false;
01322    }
01323 
01324    // Entry : 0002|0000 = group length -> recalculated
01325    ValEntry *e0002 = GetValEntry(0x0002,0x0000);
01326    if( e0002 )
01327    {
01328       std::ostringstream sLen;
01329       sLen << ComputeGroup0002Length(filetype);
01330       e0002->SetValue(sLen.str());
01331    }
01332 
01333    // Bits Allocated
01334    if ( GetEntryValue(0x0028,0x0100) ==  "12")
01335    {
01336       SetValEntry("16", 0x0028,0x0100);
01337    }
01338 
01339    int i_lgPix = GetEntryLength(GrPixel, NumPixel);
01340    if (i_lgPix != -2)
01341    {
01342       // no (GrPixel, NumPixel) element
01343       std::string s_lgPix = Util::Format("%d", i_lgPix+12);
01344       s_lgPix = Util::DicomString( s_lgPix.c_str() );
01345       InsertValEntry(s_lgPix,GrPixel, 0x0000);
01346    }
01347 
01348    // FIXME : should be nice if we could move it to File
01349    //         (or in future gdcmPixelData class)
01350 
01351    // Drop Palette Color, if necessary
01352    if ( GetEntryValue(0x0028,0x0002).c_str()[0] == '3' )
01353    {
01354       // if SamplesPerPixel = 3, sure we don't need any LUT !   
01355       // Drop 0028|1101, 0028|1102, 0028|1103
01356       // Drop 0028|1201, 0028|1202, 0028|1203
01357 
01358       DocEntry *e = GetDocEntry(0x0028,0x01101);
01359       if (e)
01360       {
01361          RemoveEntryNoDestroy(e);
01362       }
01363       e = GetDocEntry(0x0028,0x1102);
01364       if (e)
01365       {
01366          RemoveEntryNoDestroy(e);
01367       }
01368       e = GetDocEntry(0x0028,0x1103);
01369       if (e)
01370       {
01371          RemoveEntryNoDestroy(e);
01372       }
01373       e = GetDocEntry(0x0028,0x01201);
01374       if (e)
01375       {
01376          RemoveEntryNoDestroy(e);
01377       }
01378       e = GetDocEntry(0x0028,0x1202);
01379       if (e)
01380       {
01381          RemoveEntryNoDestroy(e);
01382       }
01383       e = GetDocEntry(0x0028,0x1203);
01384       if (e)
01385       {
01386           RemoveEntryNoDestroy(e);
01387       }
01388    }
01389 
01390    Document::WriteContent(fp, filetype);
01391 
01392    fp->close();
01393    delete fp;
01394 
01395    return true;
01396 }
01397 
01398 //-----------------------------------------------------------------------------
01399 // Protected
01406 void File::InitializeDefaultFile()
01407 {
01408    std::string date = Util::GetCurrentDate();
01409    std::string time = Util::GetCurrentTime();
01410    std::string uid  = Util::CreateUniqueUID();
01411    std::string uidMedia = uid;
01412    std::string uidInst  = uid;
01413    std::string uidClass = Util::CreateUniqueUID();
01414    std::string uidStudy = Util::CreateUniqueUID();
01415    std::string uidSerie = Util::CreateUniqueUID();
01416 
01417    // Meta Element Group Length
01418    InsertValEntry("146 ",                      0x0002, 0x0000);
01419    // Media Storage SOP Class UID (CT Image Storage)
01420    InsertValEntry("1.2.840.10008.5.1.4.1.1.2", 0x0002, 0x0002);
01421    // Media Storage SOP Instance UID
01422    InsertValEntry(uidMedia.c_str(),            0x0002, 0x0003);
01423    // Transfer Syntax UID (Explicit VR Little Endian)
01424    InsertValEntry("1.2.840.10008.1.2.1 ",      0x0002, 0x0010);
01425    // META Implementation Class UID
01426    InsertValEntry(uidClass.c_str(),            0x0002, 0x0012);
01427    // Source Application Entity Title
01428    InsertValEntry("GDCM",                      0x0002, 0x0016);
01429 
01430    // Instance Creation Date
01431    InsertValEntry(date.c_str(),                0x0008, 0x0012);
01432    // Instance Creation Time
01433    InsertValEntry(time.c_str(),                0x0008, 0x0013);
01434    // SOP Class UID
01435    InsertValEntry("1.2.840.10008.5.1.4.1.1.2", 0x0008, 0x0016);
01436    // SOP Instance UID
01437    InsertValEntry(uidInst.c_str(),             0x0008, 0x0018);
01438    // Modality    
01439    InsertValEntry("CT",                        0x0008, 0x0060);
01440    // Manufacturer
01441    InsertValEntry("GDCM",                      0x0008, 0x0070);
01442    // Institution Name
01443    InsertValEntry("GDCM",                      0x0008, 0x0080);
01444    // Institution Address
01445    InsertValEntry("http://www-creatis.insa-lyon.fr/Public/Gdcm", 0x0008, 0x0081);
01446 
01447    // Patient's Name
01448    InsertValEntry("GDCM",                      0x0010, 0x0010);
01449    // Patient ID
01450    InsertValEntry("GDCMID",                    0x0010, 0x0020);
01451 
01452    // Study Instance UID
01453    InsertValEntry(uidStudy.c_str(),            0x0020, 0x000d);
01454    // Series Instance UID
01455    InsertValEntry(uidSerie.c_str(),            0x0020, 0x000e);
01456    // StudyID
01457    InsertValEntry("1",                         0x0020, 0x0010);
01458    // SeriesNumber
01459    InsertValEntry("1",                         0x0020, 0x0011);
01460 
01461    // Samples per pixel 1 or 3
01462    InsertValEntry("1",                         0x0028, 0x0002);
01463    // photochromatic interpretation
01464    InsertValEntry("MONOCHROME1",               0x0028, 0x0004);
01465    // nbRows
01466    InsertValEntry("0",                         0x0028, 0x0010);
01467    // nbCols
01468    InsertValEntry("0",                         0x0028, 0x0011);
01469    // BitsAllocated 8 or 12 or 16
01470    InsertValEntry("8",                         0x0028, 0x0100);
01471    // BitsStored    <= BitsAllocated
01472    InsertValEntry("8",                         0x0028, 0x0101);
01473    // HighBit       <= BitsAllocated - 1
01474    InsertValEntry("7",                         0x0028, 0x0102);
01475    // Pixel Representation 0(unsigned) or 1(signed)
01476    InsertValEntry("0",                         0x0028, 0x0103);
01477 
01478    // default value
01479    // Special case this is the image (not a string)
01480    GrPixel = 0x7fe0;
01481    NumPixel = 0x0010;
01482    InsertBinEntry(0, 0, GrPixel, NumPixel);
01483 }
01484 
01485 //-----------------------------------------------------------------------------
01486 // Private
01492 void File::ComputeRLEInfo()
01493 {
01494    std::string ts = GetTransferSyntax();
01495    if ( !Global::GetTS()->IsRLELossless(ts) ) 
01496    {
01497       return;
01498    }
01499 
01500    // Encoded pixel data: for the time being we are only concerned with
01501    // Jpeg or RLE Pixel data encodings.
01502    // As stated in PS 3.5-2003, section 8.2 p44:
01503    // "If sent in Encapsulated Format (i.e. other than the Native Format) the
01504    //  value representation OB is used".
01505    // Hence we expect an OB value representation. Concerning OB VR,
01506    // the section PS 3.5-2003, section A.4.c p 58-59, states:
01507    // "For the Value Representations OB and OW, the encoding shall meet the
01508    //   following specifications depending on the Data element tag:"
01509    //   [...snip...]
01510    //    - the first item in the sequence of items before the encoded pixel
01511    //      data stream shall be basic offset table item. The basic offset table
01512    //      item value, however, is not required to be present"
01513    ReadAndSkipEncapsulatedBasicOffsetTable();
01514 
01515    // Encapsulated RLE Compressed Images (see PS 3.5-2003, Annex G)
01516    // Loop on the individual frame[s] and store the information
01517    // on the RLE fragments in a RLEFramesInfo.
01518    // Note: - when only a single frame is present, this is a
01519    //         classical image.
01520    //       - when more than one frame are present, then we are in 
01521    //         the case of a multi-frame image.
01522    long frameLength;
01523    while ( (frameLength = ReadTagLength(0xfffe, 0xe000)) )
01524    { 
01525       // Parse the RLE Header and store the corresponding RLE Segment
01526       // Offset Table information on fragments of this current Frame.
01527       // Note that the fragment pixels themselves are not loaded
01528       // (but just skipped).
01529       long frameOffset = Fp->tellg();
01530 
01531       uint32_t nbRleSegments = ReadInt32();
01532       if ( nbRleSegments > 16 )
01533       {
01534          // There should be at most 15 segments (refer to RLEFrame class)
01535          gdcmWarningMacro( "Too many segments.");
01536       }
01537  
01538       uint32_t rleSegmentOffsetTable[16];
01539       for( int k = 1; k <= 15; k++ )
01540       {
01541          rleSegmentOffsetTable[k] = ReadInt32();
01542       }
01543 
01544       // Deduce from both the RLE Header and the frameLength the
01545       // fragment length, and again store this info in a
01546       // RLEFramesInfo.
01547       long rleSegmentLength[15];
01548       // skipping (not reading) RLE Segments
01549       if ( nbRleSegments > 1)
01550       {
01551          for(unsigned int k = 1; k <= nbRleSegments-1; k++)
01552          {
01553              rleSegmentLength[k] =  rleSegmentOffsetTable[k+1]
01554                                   - rleSegmentOffsetTable[k];
01555              SkipBytes(rleSegmentLength[k]);
01556           }
01557        }
01558 
01559        rleSegmentLength[nbRleSegments] = frameLength 
01560                                       - rleSegmentOffsetTable[nbRleSegments];
01561        SkipBytes(rleSegmentLength[nbRleSegments]);
01562 
01563        // Store the collected info
01564        RLEFrame *newFrame = new RLEFrame;
01565        newFrame->SetNumberOfFragments(nbRleSegments);
01566        for( unsigned int uk = 1; uk <= nbRleSegments; uk++ )
01567        {
01568           newFrame->SetOffset(uk,frameOffset + rleSegmentOffsetTable[uk]);
01569           newFrame->SetLength(uk,rleSegmentLength[uk]);
01570        }
01571        RLEInfo->AddFrame(newFrame);
01572    }
01573 
01574    // Make sure that at the end of the item we encounter a 'Sequence
01575    // Delimiter Item':
01576    if ( !ReadTag(0xfffe, 0xe0dd) )
01577    {
01578       gdcmWarningMacro( "No sequence delimiter item at end of RLE item sequence");
01579    }
01580 }
01581 
01588 void File::ComputeJPEGFragmentInfo()
01589 {
01590    // If you need to, look for comments of ComputeRLEInfo().
01591    std::string ts = GetTransferSyntax();
01592    if ( ! Global::GetTS()->IsJPEG(ts) )
01593    {
01594       return;
01595    }
01596 
01597    ReadAndSkipEncapsulatedBasicOffsetTable();
01598 
01599    // Loop on the fragments[s] and store the parsed information in a
01600    // JPEGInfo.
01601    long fragmentLength;
01602    while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) )
01603    { 
01604       long fragmentOffset = Fp->tellg();
01605 
01606        // Store the collected info
01607        JPEGFragment *newFragment = new JPEGFragment;
01608        newFragment->SetOffset(fragmentOffset);
01609        newFragment->SetLength(fragmentLength);
01610        JPEGInfo->AddFragment(newFragment);
01611 
01612        SkipBytes(fragmentLength);
01613    }
01614 
01615    // Make sure that at the end of the item we encounter a 'Sequence
01616    // Delimiter Item':
01617    if ( !ReadTag(0xfffe, 0xe0dd) )
01618    {
01619       gdcmWarningMacro( "No sequence delimiter item at end of JPEG item sequence");
01620    }
01621 }
01622 
01636 bool File::ReadTag(uint16_t testGroup, uint16_t testElement)
01637 {
01638    long positionOnEntry = Fp->tellg();
01639    long currentPosition = Fp->tellg();          // On debugging purposes
01640 
01641    // Read the Item Tag group and element, and make
01642    // sure they are what we expected:
01643    uint16_t itemTagGroup;
01644    uint16_t itemTagElement;
01645    try
01646    {
01647       itemTagGroup   = ReadInt16();
01648       itemTagElement = ReadInt16();
01649    }
01650    catch ( FormatError e )
01651    {
01652       //std::cerr << e << std::endl;
01653       return false;
01654    }
01655    if ( itemTagGroup != testGroup || itemTagElement != testElement )
01656    {
01657       gdcmWarningMacro( "Wrong Item Tag found:"
01658        << "   We should have found tag ("
01659        << std::hex << testGroup << "," << testElement << ")" << std::endl
01660        << "   but instead we encountered tag ("
01661        << std::hex << itemTagGroup << "," << itemTagElement << ")"
01662        << "  at address: " << "  0x(" << (unsigned int)currentPosition  << ")" 
01663        ) ;
01664       Fp->seekg(positionOnEntry, std::ios::beg);
01665 
01666       return false;
01667    }
01668    return true;
01669 }
01670 
01685 uint32_t File::ReadTagLength(uint16_t testGroup, uint16_t testElement)
01686 {
01687 
01688    if ( !ReadTag(testGroup, testElement) )
01689    {
01690       return 0;
01691    }
01692                                                                                 
01694    long currentPosition = Fp->tellg();
01695    uint32_t itemLength  = ReadInt32();
01696    {
01697       gdcmWarningMacro( "Basic Item Length is: "
01698         << itemLength << std::endl
01699         << "  at address: " << std::hex << (unsigned int)currentPosition);
01700    }
01701    return itemLength;
01702 }
01703 
01708 void File::ReadAndSkipEncapsulatedBasicOffsetTable()
01709 {
01711    uint32_t itemLength = ReadTagLength(0xfffe, 0xe000);
01712 
01713    // When present, read the basic offset table itself.
01714    // Notes: - since the presence of this basic offset table is optional
01715    //          we can't rely on it for the implementation, and we will simply
01716    //          trash it's content (when present).
01717    //        - still, when present, we could add some further checks on the
01718    //          lengths, but we won't bother with such fuses for the time being.
01719    if ( itemLength != 0 )
01720    {
01721       char *basicOffsetTableItemValue = new char[itemLength + 1];
01722       Fp->read(basicOffsetTableItemValue, itemLength);
01723 
01724 #ifdef GDCM_DEBUG
01725       for (unsigned int i=0; i < itemLength; i += 4 )
01726       {
01727          uint32_t individualLength = str2num( &basicOffsetTableItemValue[i],
01728                                               uint32_t);
01729          gdcmWarningMacro( "Read one length: " << 
01730                           std::hex << individualLength );
01731       }
01732 #endif //GDCM_DEBUG
01733 
01734       delete[] basicOffsetTableItemValue;
01735    }
01736 }
01737 
01738 //-----------------------------------------------------------------------------
01739 // Print
01740 
01741 //-----------------------------------------------------------------------------
01742 } // end namespace gdcm

Generated on Thu Feb 10 22:17:58 2005 for gdcm by doxygen 1.3.6