Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | 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/12/21 14:52:12 $
00007   Version:   $Revision: 1.313 $
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 // Image Position (Patient) (0020,0032) VM=3
00030 // -->
00031 //  The attribute Patient Orientation (0020,0020) from the General Image Module 
00032 // is of type 2C and has the condition Required if image does not require 
00033 // Image Orientation (0020,0037) and Image Position (0020,0032). 
00034 // However, if the image does require the attributes 
00035 // - Image Orientation (Patient) (0020,0037), VM=6
00036 // - Image Position (Patient)    (0020,0032), VM=3
00037 // then attribute Patient Orientation (0020,0020) should not be present
00038 //  in the images.
00039 //
00040 // Remember also :
00041 // Patient Position (0018,5100) values :
00042 
00043 //  HFS   = Head First-Supine, where increasing (positive axis direction) :
00044 //     X -> to the direction pointed to by the patient's oustretched left arm
00045 //     Y -> to the anterior-to-posterior direction in the patient's body
00046 //     Z -> to the feet-to-head direction in the patient's body
00047 
00048 //  HFP   = Head First-Prone, where increasing (positive axis direction) :
00049 //     X -> to the direction pointed to by the patient's oustretched left arm
00050 //     Y -> to the anterior-to-posterior direction in the patient's body
00051 //     Z -> to the feet-to-head direction in the patient's body
00052 
00053 //  FFS  = Feet First-Supine, where increasing (positive axis direction) :
00054 //     X -> to the direction pointed to by the patient's oustretched left arm
00055 //     Y -> to the anterior-to-posterion direction in the patient's body
00056 //     Z -> to the feet-to-head direction in the patient's body
00057 
00058 //  FFP  = Feet First-Prone, where increasing (positive axis direction) :
00059 //     X -> to the direction pointed to by the patient's oustretched left arm
00060 //     Y -> to the posterior-to-anterior direction in the patient's body
00061 //     Z -> to the feet-to-head direction in the patient's body
00062 
00063 // HFDR = Head First-Decubitus Right
00064 // HFDL = Head First-Decubitus Left
00065 // FFDR = Feet First-Decubitus Right
00066 // FFDL = Feet First-Decubitus Left
00067 
00068 //  we can also find (non standard!)     
00069 
00070 // SEMIERECT
00071 // SUPINE
00072 
00073 // CS 2 Patient Orientation (0020 0020)
00074 //    When the coordinates of the image 
00075 //    are always present, this field is almost never used.
00076 //    Better we don't trust it too much ...
00077 //    Found Values are :
00078 //     L\P
00079 //     L\FP
00080 //     P\F
00081 //     L\F
00082 //     P\FR
00083 //     R\F
00084 //
00085 // (0020|0037) [Image Orientation (Patient)] [1\0\0\0\1\0 ]
00086 
00087                
00088 // ---------------------------------------------------------------
00089 //
00090 #include "gdcmFile.h"
00091 #include "gdcmGlobal.h"
00092 #include "gdcmUtil.h"
00093 #include "gdcmDebug.h"
00094 #include "gdcmTS.h"
00095 #include "gdcmSeqEntry.h"
00096 #include "gdcmRLEFramesInfo.h"
00097 #include "gdcmJPEGFragmentsInfo.h"
00098 #include "gdcmDataEntry.h"
00099 
00100 #include <vector>
00101 #include <stdio.h>  //sscanf
00102 #include <stdlib.h> // for atoi
00103 
00104 namespace gdcm 
00105 {
00106 
00107 //-----------------------------------------------------------------------------
00108 // Constructor / Destructor
00109 
00113 File::File():
00114    Document()
00115 {
00116    RLEInfo  = new RLEFramesInfo;
00117    JPEGInfo = new JPEGFragmentsInfo;
00118    GrPixel  = 0x7fe0;  // to avoid further troubles
00119    NumPixel = 0x0010;
00120    BasicOffsetTableItemValue = 0;
00121 }
00122 
00123 
00127 File::~File ()
00128 {
00129    if ( RLEInfo )
00130       delete RLEInfo;
00131    if ( JPEGInfo )
00132       delete JPEGInfo;
00133    delete[] BasicOffsetTableItemValue;
00134 }
00135 
00136 //-----------------------------------------------------------------------------
00137 // Public
00143 bool File::Load( ) 
00144 {
00145    if ( ! this->Document::Load( ) )
00146       return false;
00147 
00148     return DoTheLoadingJob( );   
00149 }
00150 
00156 bool File::DoTheLoadingJob( ) 
00157 {
00158    // for some ACR-NEMA images GrPixel, NumPixel is *not* 7fe0,0010
00159    // We may encounter the 'RETired' (0x0028, 0x0200) tag
00160    // (Image Location") . This entry contains the number of
00161    // the group that contains the pixel data (hence the "Pixel Data"
00162    // is found by indirection through the "Image Location").
00163    // Inside the group pointed by "Image Location" the searched element
00164    // is conventionally the element 0x0010 (when the norm is respected).
00165    // When the "Image Location" is missing we default to group 0x7fe0.
00166    // Note: this IS the right place for the code
00167  
00168    // Image Location
00169    const std::string &imgLocation = GetEntryString(0x0028, 0x0200);
00170    if ( imgLocation == GDCM_UNFOUND )
00171    {
00172       // default value
00173       GrPixel = 0x7fe0;
00174    }
00175    else
00176    {
00177       GrPixel = (uint16_t) atoi( imgLocation.c_str() );
00178    }   
00179 
00180    // sometimes Image Location value doesn't follow
00181    // the supposed processor endianness.
00182    // see gdcmData/cr172241.dcm
00183    if ( GrPixel == 0xe07f )
00184    {
00185       GrPixel = 0x7fe0;
00186    }
00187 
00188    if ( GrPixel != 0x7fe0 )
00189    {
00190       // This is a kludge for old dirty Philips imager.
00191       NumPixel = 0x1010;
00192    }
00193    else
00194    {
00195       NumPixel = 0x0010;
00196    }
00197 
00198    // Now, we know GrPixel and NumPixel.
00199    // Let's create a VirtualDictEntry to allow a further VR modification
00200    // and force VR to match with BitsAllocated.
00201    DocEntry *entry = GetDocEntry(GrPixel, NumPixel); 
00202    if ( entry != 0 )
00203    {
00204       // Compute the RLE or JPEG info
00205       OpenFile();
00206       const std::string &ts = GetTransferSyntax();
00207       Fp->seekg( entry->GetOffset(), std::ios::beg );
00208       if ( Global::GetTS()->IsRLELossless(ts) ) 
00209          ComputeRLEInfo();
00210       else if ( Global::GetTS()->IsJPEG(ts) )
00211          ComputeJPEGFragmentInfo();
00212       CloseFile();
00213 
00214       // Create a new DataEntry to change the DictEntry
00215       // The changed DictEntry will have 
00216       // - a correct PixelVR OB or OW)
00217       // - the name to "Pixel Data"
00218       DataEntry *oldEntry = dynamic_cast<DataEntry *>(entry);
00219       if (oldEntry)
00220       {
00221          VRKey PixelVR;
00222          // 8 bits allocated is a 'O Bytes' , as well as 24 (old ACR-NEMA RGB)
00223          // more than 8 (i.e 12, 16) is a 'O Words'
00224          if ( GetBitsAllocated() == 8 || GetBitsAllocated() == 24 ) 
00225             PixelVR = "OB";
00226          else
00227             PixelVR = "OW";
00228 
00229          // Change only made if usefull
00230          if ( PixelVR != oldEntry->GetVR() )
00231          {
00232             DictEntry* newDict = DictEntry::New(GrPixel,NumPixel,
00233                                                 PixelVR,"1","Pixel Data");
00234 
00235             DataEntry *newEntry = DataEntry::New(newDict);
00236             newDict->Delete();
00237             newEntry->Copy(entry);
00238             newEntry->SetBinArea(oldEntry->GetBinArea(),oldEntry->IsSelfArea());
00239             oldEntry->SetSelfArea(false);
00240 
00241             RemoveEntry(oldEntry);
00242             AddEntry(newEntry);
00243             newEntry->Delete();
00244          }
00245       }
00246    }
00247    return true;
00248 }
00257 bool File::IsReadable()
00258 {
00259    if ( !Document::IsReadable() )
00260    {
00261       return false;
00262    }
00263 
00264    const std::string &res = GetEntryString(0x0028, 0x0005);
00265    if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 )
00266    {
00267       gdcmWarningMacro("Wrong Image Dimensions" << res);
00268       return false; // Image Dimensions
00269    }
00270    bool b0028_0100 = true;
00271    if ( !GetDocEntry(0x0028, 0x0100) )
00272    {
00273       gdcmWarningMacro("Bits Allocated (0028|0100) not found"); 
00274       //return false; // "Bits Allocated"
00275       b0028_0100 = false;
00276    }
00277    bool b0028_0101 = true;
00278    if ( !GetDocEntry(0x0028, 0x0101) )
00279    {
00280       gdcmWarningMacro("Bits Stored (0028|0101) not found");
00281       //return false; // "Bits Stored"
00282       b0028_0101 = false;
00283    }
00284    bool b0028_0102 = true;
00285    if ( !GetDocEntry(0x0028, 0x0102) )
00286    {
00287       gdcmWarningMacro("Hight Bit (0028|0102) not found"); 
00288       //return false; // "High Bit"
00289       b0028_0102 = false;
00290    }
00291    bool b0028_0103 = true;
00292    if ( !GetDocEntry(0x0028, 0x0103) )
00293    {
00294       gdcmWarningMacro("Pixel Representation (0028|0103) not found");
00295       //return false; // "Pixel Representation" i.e. 'Sign' ( 0 : unsigned, 1 : signed)
00296       b0028_0103 = false;
00297    }
00298 
00299    if ( !b0028_0100 && !b0028_0101 && !b0028_0102 && !b0028_0103)
00300    {
00301       gdcmWarningMacro("Too much mandatory Tags missing !");
00302       return false;
00303    }
00304 
00305    if ( !GetDocEntry(GrPixel, NumPixel) )
00306    {
00307       gdcmWarningMacro("Pixel Dicom Element " << std::hex <<
00308                         GrPixel << "|" << NumPixel << "not found");
00309       return false; // Pixel Dicom Element not found :-(
00310    }
00311    return true;
00312 }
00313 
00318 int File::GetImageNumber()
00319 {
00320    //0020 0013 : Image Number
00321    std::string strImNumber = GetEntryString(0x0020,0x0013);
00322    if ( strImNumber != GDCM_UNFOUND )
00323    {
00324       return atoi( strImNumber.c_str() );
00325    }
00326    return 0;   //Hopeless
00327 }
00328 
00333 ModalityType File::GetModality()
00334 {
00335    // 0008 0060 : Modality
00336    std::string strModality = GetEntryString(0x0008,0x0060);
00337    if ( strModality != GDCM_UNFOUND )
00338    {
00339            if ( strModality.find("AU")  < strModality.length()) return AU;
00340       else if ( strModality.find("AS")  < strModality.length()) return AS;
00341       else if ( strModality.find("BI")  < strModality.length()) return BI;
00342       else if ( strModality.find("CF")  < strModality.length()) return CF;
00343       else if ( strModality.find("CP")  < strModality.length()) return CP;
00344       else if ( strModality.find("CR")  < strModality.length()) return CR;
00345       else if ( strModality.find("CT")  < strModality.length()) return CT;
00346       else if ( strModality.find("CS")  < strModality.length()) return CS;
00347       else if ( strModality.find("DD")  < strModality.length()) return DD;
00348       else if ( strModality.find("DF")  < strModality.length()) return DF;
00349       else if ( strModality.find("DG")  < strModality.length()) return DG;
00350       else if ( strModality.find("DM")  < strModality.length()) return DM;
00351       else if ( strModality.find("DS")  < strModality.length()) return DS;
00352       else if ( strModality.find("DX")  < strModality.length()) return DX;
00353       else if ( strModality.find("ECG") < strModality.length()) return ECG;
00354       else if ( strModality.find("EPS") < strModality.length()) return EPS;
00355       else if ( strModality.find("FA")  < strModality.length()) return FA;
00356       else if ( strModality.find("FS")  < strModality.length()) return FS;
00357       else if ( strModality.find("HC")  < strModality.length()) return HC;
00358       else if ( strModality.find("HD")  < strModality.length()) return HD;
00359       else if ( strModality.find("LP")  < strModality.length()) return LP;
00360       else if ( strModality.find("LS")  < strModality.length()) return LS;
00361       else if ( strModality.find("MA")  < strModality.length()) return MA;
00362       else if ( strModality.find("MR")  < strModality.length()) return MR;
00363       else if ( strModality.find("NM")  < strModality.length()) return NM;
00364       else if ( strModality.find("OT")  < strModality.length()) return OT;
00365       else if ( strModality.find("PT")  < strModality.length()) return PT;
00366       else if ( strModality.find("RF")  < strModality.length()) return RF;
00367       else if ( strModality.find("RG")  < strModality.length()) return RG;
00368       else if ( strModality.find("RTDOSE")   
00369                                         < strModality.length()) return RTDOSE;
00370       else if ( strModality.find("RTIMAGE")  
00371                                         < strModality.length()) return RTIMAGE;
00372       else if ( strModality.find("RTPLAN")
00373                                         < strModality.length()) return RTPLAN;
00374       else if ( strModality.find("RTSTRUCT") 
00375                                         < strModality.length()) return RTSTRUCT;
00376       else if ( strModality.find("SM")  < strModality.length()) return SM;
00377       else if ( strModality.find("ST")  < strModality.length()) return ST;
00378       else if ( strModality.find("TG")  < strModality.length()) return TG;
00379       else if ( strModality.find("US")  < strModality.length()) return US;
00380       else if ( strModality.find("VF")  < strModality.length()) return VF;
00381       else if ( strModality.find("XA")  < strModality.length()) return XA;
00382       else if ( strModality.find("XC")  < strModality.length()) return XC;
00383 
00384       else
00385       {
00388          return Unknow;
00389       }
00390    }
00391    return Unknow;
00392 }
00393 
00399 int File::GetXSize()
00400 {
00401    DataEntry *entry = GetDataEntry(0x0028,0x0011);
00402    if( entry )
00403       return (int)entry->GetValue(0);
00404    return 0;
00405 }
00406 
00413 int File::GetYSize()
00414 {
00415    DataEntry *entry = GetDataEntry(0x0028,0x0010);
00416    if( entry )
00417       return (int)entry->GetValue(0);
00418 
00419    if ( IsDicomV3() )
00420    {
00421       return 0;
00422    }
00423 
00424    // The Rows (0028,0010) entry was optional for ACR/NEMA.
00425    // (at least some images didn't have it.)
00426    // It might hence be a signal (1D image). So we default to 1:
00427    return 1;
00428 }
00429 
00438 int File::GetZSize()
00439 {
00440    // Both  DicomV3 and ACR/Nema consider the "Number of Frames"
00441    // as the third dimension.
00442    DataEntry *entry = GetDataEntry(0x0028,0x0008);
00443    if( entry )
00444       return (int)entry->GetValue(0);
00445 
00446    // We then consider the "Planes" entry as the third dimension 
00447    entry = GetDataEntry(0x0028,0x0012);
00448    if( entry )
00449       return (int)entry->GetValue(0);
00450    return 1;
00451 }
00452 
00459 float File::GetXSpacing()
00460 {
00461    float xspacing = 1.0;
00462    uint32_t nbValue;
00463 
00464    // To follow David Clunie's advice, we first check ImagerPixelSpacing
00465 
00466    DataEntry *entry = GetDataEntry(0x0018,0x1164);
00467    if( entry )
00468    {
00469       nbValue = entry->GetValueCount();
00470       // Can't use IsValueCountValid because of the complex heuristic.
00471       if( nbValue !=2 )
00472          gdcmWarningMacro("ImagerPixelSpacing (0x0018,0x1164) "
00473          << "has a wrong number of values :" << nbValue);
00474      
00475       if( nbValue >= 3 )
00476          xspacing = (float)entry->GetValue(2);
00477       else if( nbValue >= 2 )
00478          xspacing = (float)entry->GetValue(1);
00479       else
00480          xspacing = (float)entry->GetValue(0);
00481 
00482       if ( xspacing == 0.0 )
00483          xspacing = 1.0;
00484       return xspacing;
00485    }
00486    else
00487    {
00488       gdcmWarningMacro( "Unfound Imager Pixel Spacing (0018,1164)" );
00489    }
00490 
00491    entry = GetDataEntry(0x0028,0x0030);
00492    if( entry )
00493    {
00494       nbValue = entry->GetValueCount();
00495       if( nbValue !=2 )
00496          gdcmWarningMacro("PixelSpacing (0x0018,0x0030) "
00497           << "has a wrong number of values :" << nbValue);      
00498       
00499       if( nbValue >= 3 )
00500          xspacing = (float)entry->GetValue(2);
00501       else if( nbValue >= 2 )
00502          xspacing = (float)entry->GetValue(1);
00503       else
00504          xspacing = (float)entry->GetValue(0);
00505 
00506       if ( xspacing == 0.0 )
00507          xspacing = 1.0;
00508       return xspacing;
00509    }
00510    else
00511    {
00512       gdcmWarningMacro( "Unfound Pixel Spacing (0028,0030)" );
00513    }
00514 
00515    return xspacing;
00516 }
00517 
00524 float File::GetYSpacing()
00525 {
00526    float yspacing = 1.0;
00527    // To follow David Clunie's advice, we first check ImagerPixelSpacing
00528 
00529    DataEntry *entry = GetDataEntry(0x0018,0x1164);
00530    if( entry )
00531    {
00532       yspacing = (float)entry->GetValue(0);
00533 
00534       if ( yspacing == 0.0 )
00535          yspacing = 1.0;
00536       return yspacing;
00537    }
00538    else
00539    {
00540       gdcmWarningMacro( "Unfound Imager Pixel Spacing (0018,1164)" );
00541    }
00542 
00543    entry = GetDataEntry(0x0028,0x0030);
00544    if( entry )
00545    {
00546       yspacing = (float)entry->GetValue(0);
00547 
00548       if ( yspacing == 0.0 )
00549          yspacing = 1.0;
00550       return yspacing;
00551    }
00552    else
00553    {
00554       gdcmWarningMacro( "Unfound Pixel Spacing (0028,0030)" );
00555    }
00556 
00557    return yspacing;
00558 } 
00559 
00574 float File::GetZSpacing()
00575 {
00576 
00577    float zspacing = 1.0f;
00578 
00579    // Spacing Between Slices : distance between the middle of 2 slices
00580    // Slices may be :
00581    //   jointives     (Spacing between Slices = Slice Thickness)
00582    //   overlapping   (Spacing between Slices < Slice Thickness)
00583    //   disjointes    (Spacing between Slices > Slice Thickness)
00584    // Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal
00585    //   It only concerns the MRI guys, not people wanting to visualize volumes
00586    //   If Spacing Between Slices is missing, 
00587    //   we suppose slices joint together
00588    DataEntry *entry = GetDataEntry(0x0018,0x0088);
00589    if( entry )
00590    {
00591       zspacing = (float)entry->GetValue(0);
00592 
00593       if ( zspacing == 0.0 )
00594          zspacing = 1.0;
00595       return zspacing;
00596    }
00597    else
00598       gdcmWarningMacro("Unfound Spacing Between Slices (0018,0088)");
00599 
00600    // if no 'Spacing Between Slices' is found, 
00601    // we assume slices join together
00602    // (no overlapping, no interslice gap)
00603    entry = GetDataEntry(0x0018,0x0050);
00604    if( entry )
00605    {
00606       zspacing = (float)entry->GetValue(0);
00607 
00608       if ( zspacing == 0.0 )
00609          zspacing = 1.0;
00610       return zspacing;
00611    }
00612    else
00613       gdcmWarningMacro("Unfound Slice Thickness (0018,0050)");
00614 
00615    // if no 'Spacing Between Slices' is found, 
00616    // we assume slices join together
00617    // (no overlapping, no interslice gap)
00618    entry = GetDataEntry(0x3004,0x000c);
00619    if( entry )
00620    {
00621       float z1 = (float)entry->GetValue(0);
00622       float z2 = (float)entry->GetValue(1);
00623       zspacing = z2 - z1; // can be negative...
00624 
00625       if ( zspacing == 0.0 )
00626          zspacing = 1.0;
00627       return zspacing;
00628    }
00629 
00630    return zspacing;
00631 }
00632 
00639 float File::GetXOrigin()
00640 {
00641    DataEntry *entry = GetDataEntry(0x0020,0x0032);
00642    if( !entry )
00643    {
00644       gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
00645       entry = GetDataEntry(0x0020,0x0030);
00646       if( !entry )
00647       {
00648          gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
00649          return 0.0f;
00650       }
00651    }
00652 
00653    if( entry->GetValueCount() == 3 )
00654    {
00655       if (!entry->IsValueCountValid() )
00656       {
00657          gdcmErrorMacro( "Invalid Value Count" );
00658       }
00659       return (float)entry->GetValue(0);
00660    }
00661    return 0.0f;
00662 }
00663 
00670 float File::GetYOrigin()
00671 {
00672    DataEntry *entry = GetDataEntry(0x0020,0x0032);
00673    if( !entry )
00674    {
00675       gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
00676       entry = GetDataEntry(0x0020,0x0030);
00677       if( !entry )
00678       {
00679          gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
00680          return 0.0f;
00681       }
00682    }
00683 
00684    if( entry->GetValueCount() == 3 )
00685    {
00686       if (!entry->IsValueCountValid() )
00687       {
00688          gdcmErrorMacro( "Invalid Value Count" );
00689       }
00690       return (float)entry->GetValue(1);
00691    }
00692    return 0.0f;
00693 }
00694 
00703 float File::GetZOrigin()
00704 {
00705    DataEntry *entry = GetDataEntry(0x0020,0x0032);
00706    if( entry )
00707    {
00708       if( entry->GetValueCount() == 3 )
00709       {
00710          if (!entry->IsValueCountValid() )
00711          {
00712             gdcmErrorMacro( "Invalid Value Count" );
00713          }
00714          return (float)entry->GetValue(2);
00715       }
00716       gdcmWarningMacro( "Wrong Image Position Patient (0020,0032)");
00717       return 0.0f;
00718    }
00719 
00720    entry = GetDataEntry(0x0020,0x0030);
00721    if( entry )
00722    {
00723       if( entry->GetValueCount() == 3 )
00724       {
00725          if (!entry->IsValueCountValid() )
00726          {
00727             gdcmErrorMacro( "Invalid Value Count" );
00728          }
00729          return (float)entry->GetValue(2);
00730       }
00731       gdcmWarningMacro( "Wrong Image Position (RET) (0020,0030)");
00732       return 0.0f;
00733    }
00734 
00735    // for *very* old ACR-NEMA images
00736    entry = GetDataEntry(0x0020,0x1041);
00737    if( entry )
00738    {
00739       if( entry->GetValueCount() == 1 )
00740       {
00741          if (!entry->IsValueCountValid() )
00742          {
00743             gdcmErrorMacro( "Invalid Value Count" );
00744          }
00745          return (float)entry->GetValue(0); // VM=1 !
00746       }
00747       gdcmWarningMacro( "Wrong Slice Location (0020,1041)");
00748       return 0.0f;
00749    }
00750 
00751    entry = GetDataEntry(0x0020,0x0050);
00752    if( entry )
00753    {
00754       if( entry->GetValueCount() == 1 )
00755       {
00756          if (!entry->IsValueCountValid() )
00757          {
00758             gdcmErrorMacro( "Invalid Value Count" );
00759          }
00760          return (float)entry->GetValue(0);
00761       }
00762       gdcmWarningMacro( "Wrong Location (0020,0050)");
00763       return 0.0f;
00764    }
00765    return 0.; // Hopeless
00766 }
00767 
00780 bool File::GetImageOrientationPatient( float iop[6] )
00781 {
00782    std::string strImOriPat;
00783    //iop is supposed to be float[6]
00784 
00785    // 0020 0037 DS REL Image Orientation (Patient)
00786    if ( (strImOriPat = GetEntryString(0x0020,0x0037)) != GDCM_UNFOUND )
00787    {
00788       if ( sscanf( strImOriPat.c_str(), "%f \\ %f \\%f \\%f \\%f \\%f ", 
00789           &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 )
00790       {
00791          iop[0] = iop[4] = 1.;
00792          iop[1] = iop[2] = iop[3] = iop[5] = 0.;
00793          gdcmWarningMacro( "Wrong Image Orientation Patient (0020,0037)."
00794                         << " Less than 6 values were found." );
00795          return false;
00796       }
00797       else 
00798          return true;
00799    }
00800    //For ACR-NEMA
00801    // 0020 0035 DS REL Image Orientation (RET)
00802    else if ( (strImOriPat = GetEntryString(0x0020,0x0035)) != GDCM_UNFOUND )
00803    {
00804       if ( sscanf( strImOriPat.c_str(), "%f \\ %f \\%f \\%f \\%f \\%f ", 
00805           &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 )
00806       {
00807          iop[0] = iop[4] = 1.;
00808          iop[1] = iop[2] = iop[3] = iop[5] = 0.;
00809          gdcmWarningMacro( "wrong Image Orientation Patient (0020,0035). "
00810                         << "Less than 6 values were found." );
00811          return false;
00812       }
00813       else
00814          return true;
00815    }
00816    return false;
00817 }
00818 
00825 int File::GetBitsStored()
00826 {
00827    DataEntry *entry = GetDataEntry(0x0028,0x0101);
00828    if( !entry )
00829    {
00830       gdcmWarningMacro("BitsStored (0028,0101) is supposed to be mandatory");
00831       return 0;
00832    }
00833    return (int)entry->GetValue(0);
00834 }
00835 
00842 int File::GetBitsAllocated()
00843 {
00844    DataEntry *entry = GetDataEntry(0x0028,0x0100);
00845    if( !entry )
00846    {
00847       gdcmWarningMacro("BitsAllocated (0028,0100) is supposed to be mandatory");
00848       return 0;
00849    }
00850    return (int)entry->GetValue(0);
00851 }
00852 
00859 int File::GetHighBitPosition()
00860 {
00861    DataEntry *entry = GetDataEntry(0x0028,0x0102);
00862    if( !entry )
00863    {
00864       gdcmWarningMacro("HighBitPosition (0028,0102) is supposed to be mandatory");
00865       return 0;
00866    }
00867    return (int)entry->GetValue(0);
00868 }
00869 
00876 int File::GetSamplesPerPixel()
00877 {
00878    DataEntry *entry = GetDataEntry(0x0028,0x0002);
00879    if( !entry )
00880    {
00881       gdcmWarningMacro("SamplesPerPixel (0028,0002) is supposed to be mandatory");
00882       return 1; // Well, it's supposed to be mandatory ...
00883                 // but sometimes it's missing : *we* assume Gray pixels
00884    }
00885    return (int)entry->GetValue(0);
00886 }
00887 
00893 int File::GetPlanarConfiguration()
00894 {
00895    DataEntry *entry = GetDataEntry(0x0028,0x0006);
00896    if( !entry )
00897    {
00898       return 0;
00899    }
00900    return (int)entry->GetValue(0);
00901 }
00902 
00908 int File::GetPixelSize()
00909 {
00910    // 0028 0100 US IMG Bits Allocated
00911    // (in order no to be messed up by old ACR-NEMA RGB images)
00912    assert( !(GetEntryString(0x0028,0x0100) == "24") );
00913 
00914    std::string pixelType = GetPixelType();
00915    if ( pixelType ==  "8U" || pixelType == "8S" )
00916    {
00917       return 1;
00918    }
00919    if ( pixelType == "16U" || pixelType == "16S")
00920    {
00921       return 2;
00922    }
00923    if ( pixelType == "32U" || pixelType == "32S")
00924    {
00925       return 4;
00926    }
00927    if ( pixelType == "FD" )
00928    {
00929       return 8;
00930    }
00931    gdcmWarningMacro( "Unknown pixel type: " << pixelType);
00932    return 0;
00933 }
00934 
00950 std::string File::GetPixelType()
00951 {
00952    std::string bitsAlloc = GetEntryString(0x0028, 0x0100); // Bits Allocated
00953    if ( bitsAlloc == GDCM_UNFOUND )
00954    {
00955       gdcmWarningMacro( "Bits Allocated (0028,0100) supposed to be mandatory");
00956       bitsAlloc = "16"; // default and arbitrary value, not to polute the output
00957    }
00958 
00959    if ( bitsAlloc == "64" )
00960    {
00961       return "FD";
00962    }
00963    else if ( bitsAlloc == "12" )
00964    {
00965       // It will be unpacked
00966       bitsAlloc = "16";
00967    }
00968    else if ( bitsAlloc == "24" )
00969    {
00970       // (in order no to be messed up by old RGB images)
00971       bitsAlloc = "8";
00972    }
00973 
00974    std::string sign;
00975    if( IsSignedPixelData() )
00976    {
00977       sign = "S";
00978    }
00979    else
00980    {
00981       sign = "U";
00982    }
00983    return bitsAlloc + sign;
00984 }
00985 
00994 bool File::IsSignedPixelData()
00995 {
00996    DataEntry *entry = GetDataEntry(0x0028, 0x0103);//"Pixel Representation"
00997    if( !entry )
00998    {
00999       gdcmWarningMacro( "Pixel Representation (0028,0103) supposed to be "
01000                       << "mandatory");
01001       return false;
01002    }
01003    return entry->GetValue(0) != 0;
01004 }
01005 
01011 bool File::IsMonochrome()
01012 {
01013    const std::string &PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
01014    if (  Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1")
01015       || Util::DicomStringEqual(PhotometricInterp, "MONOCHROME2") )
01016    {
01017       return true;
01018    }
01019    if ( PhotometricInterp == GDCM_UNFOUND )
01020    {
01021       gdcmWarningMacro( "Photometric Interpretation (0028,0004) supposed to be "
01022                          << "mandatory");
01023    }
01024    return false;
01025 }
01026 
01032 bool File::IsMonochrome1()
01033 {
01034    const std::string &PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
01035    if (  Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1") )
01036    {
01037       return true;
01038    }
01039    if ( PhotometricInterp == GDCM_UNFOUND )
01040    {
01041       gdcmWarningMacro( "Photometric Interpretation (0028,0004) : supposed to"
01042       << " be mandatory! ");
01043    }
01044    return false;
01045 }
01046 
01052 bool File::IsPaletteColor()
01053 {
01054    std::string PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
01055    if (   PhotometricInterp == "PALETTE COLOR " )
01056    {
01057       return true;
01058    }
01059    if ( PhotometricInterp == GDCM_UNFOUND )
01060    {
01061       gdcmDebugMacro( "Not found : Palette color (0028,0004)");
01062    }
01063    return false;
01064 }
01065 
01071 bool File::IsYBRFull()
01072 {
01073    std::string PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
01074    if (   PhotometricInterp == "YBR_FULL" )
01075    {
01076       return true;
01077    }
01078    if ( PhotometricInterp == GDCM_UNFOUND )
01079    {
01080       gdcmDebugMacro( "Not found : YBR Full (0028,0004)");
01081    }
01082    return false;
01083 }
01084 
01093 bool File::HasLUT()
01094 {
01095    // Check the presence of the LUT Descriptors, and LUT Tables    
01096    // LutDescriptorRed    
01097    if ( !GetDocEntry(0x0028,0x1101) )
01098    {
01099       return false;
01100    }
01101    // LutDescriptorGreen 
01102    if ( !GetDocEntry(0x0028,0x1102) )
01103    {
01104       return false;
01105    }
01106    // LutDescriptorBlue 
01107    if ( !GetDocEntry(0x0028,0x1103) )
01108    {
01109       return false;
01110    }
01111    // Red Palette Color Lookup Table Data
01112    if ( !GetDocEntry(0x0028,0x1201) )
01113    {
01114       return false;
01115    }
01116    // Green Palette Color Lookup Table Data       
01117    if ( !GetDocEntry(0x0028,0x1202) )
01118    {
01119       return false;
01120    }
01121    // Blue Palette Color Lookup Table Data      
01122    if ( !GetDocEntry(0x0028,0x1203) )
01123    {
01124       return false;
01125    }
01126 
01127    // FIXME : (0x0028,0x3006) : LUT Data (CTX dependent)
01128    //         NOT taken into account, but we don't know how to use it ...   
01129    return true;
01130 }
01131 
01139 int File::GetLUTNbits()
01140 {
01141    std::vector<std::string> tokens;
01142    int lutNbits;
01143 
01144    //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red
01145    //                                = Lookup Table Desc-Blue
01146    // Consistency already checked in GetLUTLength
01147    std::string lutDescription = GetEntryString(0x0028,0x1101);
01148    if ( lutDescription == GDCM_UNFOUND )
01149    {
01150       return 0;
01151    }
01152 
01153    tokens.clear(); // clean any previous value
01154    Util::Tokenize ( lutDescription, tokens, "\\" );
01155    //LutLength=atoi(tokens[0].c_str());
01156    //LutDepth=atoi(tokens[1].c_str());
01157 
01158    lutNbits = atoi( tokens[2].c_str() );
01159    tokens.clear();
01160 
01161    return lutNbits;
01162 }
01163 
01168 float File::GetRescaleIntercept()
01169 {
01170    // 0028 1052 DS IMG Rescale Intercept
01171    DataEntry *entry = GetDataEntry(0x0028, 0x1052);
01172    if( !entry )
01173    {
01174       gdcmWarningMacro( "Missing Rescale Intercept (0028,1052)");
01175       return 0.0f;
01176    }
01177    return (float)entry->GetValue(0);
01178 
01179 }
01180 
01185 float File::GetRescaleSlope()
01186 {
01187    // 0028 1053 DS IMG Rescale Slope
01188    DataEntry *entry = GetDataEntry(0x0028, 0x1053);
01189    if( !entry )
01190    {
01191       gdcmDebugMacro( "Missing Rescale Slope (0028,1053)");
01192       return 1.0f;
01193    }
01194    return (float)entry->GetValue(0);
01195 }
01196 
01204 int File::GetNumberOfScalarComponents()
01205 {
01206    if ( GetSamplesPerPixel() == 3 )
01207    {
01208       return 3;
01209    }
01210 
01211    // 0028 0100 US IMG Bits Allocated
01212    // (in order no to be messed up by old RGB images)
01213    if ( GetEntryString(0x0028,0x0100) == "24" )
01214    {
01215       return 3;
01216    }
01217 
01218    std::string strPhotometricInterpretation = GetEntryString(0x0028,0x0004);
01219 
01220    if ( ( strPhotometricInterpretation == "PALETTE COLOR ") )
01221    {
01222       if ( HasLUT() )// PALETTE COLOR is NOT enough
01223       {
01224          return 3;
01225       }
01226       else
01227       {
01228          return 1;
01229       }
01230    }
01231 
01232    // beware of trailing space at end of string      
01233    // DICOM tags are never of odd length
01234    if ( strPhotometricInterpretation == GDCM_UNFOUND   || 
01235         Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME1") ||
01236         Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME2") )
01237    {
01238       return 1;
01239    }
01240    else
01241    {
01242       // we assume that *all* kinds of YBR are dealt with
01243       return 3;
01244    }
01245 }
01246 
01254 int File::GetNumberOfScalarComponentsRaw()
01255 {
01256    // 0028 0100 US IMG Bits Allocated
01257    // (in order no to be messed up by old RGB images)
01258    if ( File::GetEntryString(0x0028,0x0100) == "24" )
01259    {
01260       return 3;
01261    }
01262 
01263    // we assume that *all* kinds of YBR are dealt with
01264    return GetSamplesPerPixel();
01265 }
01266 
01272 size_t File::GetPixelOffset()
01273 {
01274    DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel);
01275    if ( pxlElement )
01276    {
01277       return pxlElement->GetOffset();
01278    }
01279    else
01280    {
01281       gdcmWarningMacro( "Big trouble : Pixel Element ("
01282                       << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" );
01283       return 0;
01284    }
01285 }
01286 
01294 size_t File::GetPixelAreaLength()
01295 {
01296    DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel);
01297    if ( pxlElement )
01298    {
01299       return pxlElement->GetLength();
01300    }
01301    else
01302    {
01303       gdcmWarningMacro( "Big trouble : Pixel Element ("
01304                       << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" );
01305       return 0;
01306    }
01307 }
01308 
01315 void File::AddAnonymizeElement (uint16_t group, uint16_t elem, 
01316                                 std::string const &value) 
01317 { 
01318    DicomElement el;
01319    el.Group = group;
01320    el.Elem  = elem;
01321    el.Value = value;
01322    UserAnonymizeList.push_back(el); 
01323 }
01324 
01329 void File::AnonymizeNoLoad()
01330 {
01331    std::fstream *fp = new std::fstream(Filename.c_str(), 
01332                               std::ios::in | std::ios::out | std::ios::binary); 
01333    gdcm::DocEntry *d;
01334    uint32_t offset;
01335    uint32_t lgth;
01336    uint32_t valLgth = 0;
01337    std::string *spaces;
01338    for (ListElements::iterator it = UserAnonymizeList.begin();  
01339                                it != UserAnonymizeList.end();
01340                              ++it)
01341    { 
01342       d = GetDocEntry( (*it).Group, (*it).Elem);
01343 
01344       if ( d == NULL)
01345          continue;
01346 
01347       if ( dynamic_cast<SeqEntry *>(d) )
01348       {
01349          gdcmWarningMacro( "You cannot 'Anonymize' a SeqEntry ");
01350          continue;
01351       }
01352 
01353       offset = d->GetOffset();
01354       lgth =   d->GetLength();
01355       if (valLgth < lgth)
01356       {
01357          spaces = new std::string( lgth-valLgth, ' ');
01358          (*it).Value = (*it).Value + *spaces;
01359          delete spaces;
01360       }
01361       fp->seekp( offset, std::ios::beg );
01362       fp->write( (*it).Value.c_str(), lgth );
01363      
01364    }
01365    fp->close();
01366    delete fp;
01367 }
01368 
01374 bool File::AnonymizeFile()
01375 {
01376    // If Anonymisation list is empty, let's perform some basic anonymization
01377    if ( UserAnonymizeList.begin() == UserAnonymizeList.end() )
01378    {
01379       // If exist, replace by spaces
01380       SetEntryString("  ",0x0010, 0x2154); // Telephone   
01381       SetEntryString("  ",0x0010, 0x1040); // Adress
01382       SetEntryString("  ",0x0010, 0x0020); // Patient ID
01383 
01384       DocEntry *patientNameHE = GetDocEntry (0x0010, 0x0010);
01385   
01386       if ( patientNameHE ) // we replace it by Study Instance UID (why not ?)
01387       {
01388          std::string studyInstanceUID =  GetEntryString (0x0020, 0x000d);
01389          if ( studyInstanceUID != GDCM_UNFOUND )
01390          {
01391             SetEntryString(studyInstanceUID, 0x0010, 0x0010);
01392          }
01393          else
01394          {
01395             SetEntryString("anonymized", 0x0010, 0x0010);
01396          }
01397       }
01398    }
01399    else
01400    {
01401       gdcm::DocEntry *d;
01402       for (ListElements::iterator it = UserAnonymizeList.begin();  
01403                                   it != UserAnonymizeList.end();
01404                                 ++it)
01405       {  
01406          d = GetDocEntry( (*it).Group, (*it).Elem);
01407 
01408          if ( d == NULL)
01409             continue;
01410 
01411          if ( dynamic_cast<SeqEntry *>(d) )
01412          {
01413             gdcmWarningMacro( "You cannot 'Anonymize' a SeqEntry ");
01414             continue;
01415          }
01416 
01417          if ( dynamic_cast<DataEntry *>(d) )
01418          {
01419             gdcmWarningMacro( "To 'Anonymize' a DataEntry, better use AnonymizeNoLoad (FIXME) ");
01420             continue;
01421          }
01422          else
01423             SetEntryString ((*it).Value, (*it).Group, (*it).Elem);
01424       }
01425 }
01426 
01427   // In order to make definitively impossible any further identification
01428   // remove or replace all the stuff that contains a Date
01429 
01430 //0008 0012 DA ID Instance Creation Date
01431 //0008 0020 DA ID Study Date
01432 //0008 0021 DA ID Series Date
01433 //0008 0022 DA ID Acquisition Date
01434 //0008 0023 DA ID Content Date
01435 //0008 0024 DA ID Overlay Date
01436 //0008 0025 DA ID Curve Date
01437 //0008 002a DT ID Acquisition Datetime
01438 //0018 9074 DT ACQ Frame Acquisition Datetime
01439 //0018 9151 DT ACQ Frame Reference Datetime
01440 //0018 a002 DT ACQ Contribution Date Time
01441 //0020 3403 SH REL Modified Image Date (RET)
01442 //0032 0032 DA SDY Study Verified Date
01443 //0032 0034 DA SDY Study Read Date
01444 //0032 1000 DA SDY Scheduled Study Start Date
01445 //0032 1010 DA SDY Scheduled Study Stop Date
01446 //0032 1040 DA SDY Study Arrival Date
01447 //0032 1050 DA SDY Study Completion Date
01448 //0038 001a DA VIS Scheduled Admission Date
01449 //0038 001c DA VIS Scheduled Discharge Date
01450 //0038 0020 DA VIS Admitting Date
01451 //0038 0030 DA VIS Discharge Date
01452 //0040 0002 DA PRC Scheduled Procedure Step Start Date
01453 //0040 0004 DA PRC Scheduled Procedure Step End Date
01454 //0040 0244 DA PRC Performed Procedure Step Start Date
01455 //0040 0250 DA PRC Performed Procedure Step End Date
01456 //0040 2004 DA PRC Issue Date of Imaging Service Request
01457 //0040 4005 DT PRC Scheduled Procedure Step Start Date and Time
01458 //0040 4011 DT PRC Expected Completion Date and Time
01459 //0040 a030 DT PRC Verification Date Time
01460 //0040 a032 DT PRC Observation Date Time
01461 //0040 a120 DT PRC DateTime
01462 //0040 a121 DA PRC Date
01463 //0040 a13a DT PRC Referenced Datetime
01464 //0070 0082 DA ??? Presentation Creation Date
01465 //0100 0420 DT ??? SOP Autorization Date and Time
01466 //0400 0105 DT ??? Digital Signature DateTime
01467 //2100 0040 DA PJ Creation Date
01468 //3006 0008 DA SSET Structure Set Date
01469 //3008 0024 DA ??? Treatment Control Point Date
01470 //3008 0054 DA ??? First Treatment Date
01471 //3008 0056 DA ??? Most Recent Treatment Date
01472 //3008 0162 DA ??? Safe Position Exit Date
01473 //3008 0166 DA ??? Safe Position Return Date
01474 //3008 0250 DA ??? Treatment Date
01475 //300a 0006 DA RT RT Plan Date
01476 //300a 022c DA RT Air Kerma Rate Reference Date
01477 //300e 0004 DA RT Review Date
01478 
01479    return true;
01480 }
01481 
01490 bool File::Write(std::string fileName, FileType writetype)
01491 {
01492    std::ofstream *fp = new std::ofstream(fileName.c_str(), 
01493                                          std::ios::out | std::ios::binary);
01494    if (*fp == NULL)
01495    {
01496       gdcmWarningMacro("Failed to open (write) File: " << fileName.c_str());
01497       return false;
01498    }
01499 
01500    // Entry : 0002|0000 = group length -> recalculated
01501    DataEntry *e0000 = GetDataEntry(0x0002,0x0000);
01502    if ( e0000 )
01503    {
01504       std::ostringstream sLen;
01505       sLen << ComputeGroup0002Length( );
01506       e0000->SetString(sLen.str());
01507    }
01508 
01510    if( writetype != JPEG )
01511    {
01512       int i_lgPix = GetEntryLength(GrPixel, NumPixel);
01513       if (i_lgPix != -2)
01514       {
01515          // no (GrPixel, NumPixel) element
01516          std::string s_lgPix = Util::Format("%d", i_lgPix+12);
01517          s_lgPix = Util::DicomString( s_lgPix.c_str() );
01518          InsertEntryString(s_lgPix,GrPixel, 0x0000);   
01519       }
01520    }
01521    Document::WriteContent(fp, writetype);
01522 
01523    fp->close();
01524    delete fp;
01525 
01526    return true;
01527 }
01528 
01529 
01530 //-----------------------------------------------------------------------------
01531 // Protected
01532 
01533 
01534 //-----------------------------------------------------------------------------
01535 // Private
01541 void File::ComputeRLEInfo()
01542 {
01543    std::string ts = GetTransferSyntax();
01544    if ( !Global::GetTS()->IsRLELossless(ts) ) 
01545    {
01546       return;
01547    }
01548 
01549    // Encoded pixel data: for the time being we are only concerned with
01550    // Jpeg or RLE Pixel data encodings.
01551    // As stated in PS 3.5-2003, section 8.2 p44:
01552    // "If sent in Encapsulated Format (i.e. other than the Native Format) the
01553    //  value representation OB is used".
01554    // Hence we expect an OB value representation. Concerning OB VR,
01555    // the section PS 3.5-2003, section A.4.c p 58-59, states:
01556    // "For the Value Representations OB and OW, the encoding shall meet the
01557    //   following specifications depending on the Data element tag:"
01558    //   [...snip...]
01559    //    - the first item in the sequence of items before the encoded pixel
01560    //      data stream shall be basic offset table item. The basic offset table
01561    //      item value, however, is not required to be present"
01562    ReadEncapsulatedBasicOffsetTable();
01563 
01564    // Encapsulated RLE Compressed Images (see PS 3.5-2003, Annex G)
01565    // Loop on the individual frame[s] and store the information
01566    // on the RLE fragments in a RLEFramesInfo.
01567    // Note: - when only a single frame is present, this is a
01568    //         classical image.
01569    //       - when more than one frame are present, then we are in 
01570    //         the case of a multi-frame image.
01571    long frameLength;
01572    int i=0;
01573    uint32_t sum = 0;
01574    while ( (frameLength = ReadTagLength(0xfffe, 0xe000)) != 0 )
01575    { 
01576       // Since we have read the basic offset table, let's check the value were correct
01577       // or else produce a warning:
01578       if ( BasicOffsetTableItemValue )
01579         {
01580         // If a BasicOffsetTableItemValue was read
01581         uint32_t individualLength = BasicOffsetTableItemValue[i];
01582         assert( individualLength == sum ); // REMOVE that if this is a problem
01583         if( individualLength != sum )
01584           {
01585           gdcmWarningMacro( "BasicOffsetTableItemValue differs from the fragment lenght" );
01586           }
01587         sum += frameLength + 8;
01588         i++;
01589         }
01590       // Parse the RLE Header and store the corresponding RLE Segment
01591       // Offset Table information on fragments of this current Frame.
01592       // Note that the fragment pixels themselves are not loaded
01593       // (but just skipped).
01594       long frameOffset = Fp->tellg();
01595 
01596       uint32_t nbRleSegments = ReadInt32();
01597       if ( nbRleSegments > 16 )
01598       {
01599          // There should be at most 15 segments (refer to RLEFrame class)
01600          gdcmWarningMacro( "Too many segments.");
01601       }
01602  
01603       uint32_t rleSegmentOffsetTable[16];
01604       for( int k = 1; k <= 15; k++ )
01605       {
01606          rleSegmentOffsetTable[k] = ReadInt32();
01607       }
01608 
01609       // Deduce from both RLE Header and frameLength 
01610       // the fragment length, and again store this info
01611       // in a RLEFramesInfo.
01612       long rleSegmentLength[15];
01613       // skipping (not reading) RLE Segments
01614       if ( nbRleSegments > 1)
01615       {
01616          for(unsigned int k = 1; k <= nbRleSegments-1; k++)
01617          {
01618              rleSegmentLength[k] =  rleSegmentOffsetTable[k+1]
01619                                   - rleSegmentOffsetTable[k];
01620              SkipBytes(rleSegmentLength[k]);
01621           }
01622        }
01623 
01624        rleSegmentLength[nbRleSegments] = frameLength 
01625                                       - rleSegmentOffsetTable[nbRleSegments];
01626        SkipBytes(rleSegmentLength[nbRleSegments]);
01627 
01628        // Store the collected info
01629        RLEFrame *newFrame = new RLEFrame;
01630        newFrame->SetNumberOfFragments(nbRleSegments);
01631        for( unsigned int uk = 1; uk <= nbRleSegments; uk++ )
01632        {
01633           newFrame->SetOffset(uk,frameOffset + rleSegmentOffsetTable[uk]);
01634           newFrame->SetLength(uk,rleSegmentLength[uk]);
01635        }
01636        RLEInfo->AddFrame(newFrame);
01637    }
01638 
01639    // Make sure that  we encounter a 'Sequence Delimiter Item'
01640    // at the end of the item :
01641    if ( !ReadTag(0xfffe, 0xe0dd) )
01642    {
01643       gdcmWarningMacro( "No sequence delimiter item at end of RLE item sequence");
01644    }
01645 }
01646 
01653 void File::ComputeJPEGFragmentInfo()
01654 {
01655    // If you need to, look for comments of ComputeRLEInfo().
01656    std::string ts = GetTransferSyntax();
01657    if ( ! Global::GetTS()->IsJPEG(ts) )
01658    {
01659       return;
01660    }
01661 
01662    ReadEncapsulatedBasicOffsetTable();
01663 
01664    // Loop on the fragments[s] and store the parsed information in a
01665    // JPEGInfo.
01666    long fragmentLength;
01667    int i=0;
01668    uint32_t sum = 0;
01669    while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) != 0 )
01670    { 
01671       // Since we have read the basic offset table, let's check the value were correct
01672       // or else produce a warning:
01673       // A.4 Transfer syntaxes for encapsulation of encoded pixel data:
01674       // When the Item Value is present, the Basic Offset Table Item Value shall contain
01675       // concatenated 32-bit unsigned integer values that are byte offsets to the first
01676       // byte of the Item Tag of the first fragment for each frame in the Sequence of
01677       // Items. These offsets are measured from the first byte of the first Item Tag
01678       // following the Basic Offset Table item (See Table A.4-2).
01679 
01680       if ( BasicOffsetTableItemValue )
01681         {
01682         // If a BasicOffsetTableItemValue was read
01683         uint32_t individualLength = BasicOffsetTableItemValue[i];
01684         //assert( individualLength == sum ); // Seems like 00191113.dcm is off by one ??
01685         if( individualLength != sum )
01686           {
01687           gdcmWarningMacro( "BasicOffsetTableItemValue differs from the fragment lenght:" <<
01688               individualLength << " != " << sum );
01689           }
01690         sum += fragmentLength + 8;
01691         i++;
01692         }
01693 
01694       long fragmentOffset = Fp->tellg();
01695       // Store the collected info
01696       JPEGFragment *newFragment = new JPEGFragment;
01697       newFragment->SetOffset(fragmentOffset);
01698       newFragment->SetLength(fragmentLength);
01699       JPEGInfo->AddFragment(newFragment);
01700 
01701       SkipBytes(fragmentLength);
01702    }
01703 
01704    // Make sure that  we encounter a 'Sequence Delimiter Item'
01705    // at the end of the item :
01706    if ( !ReadTag(0xfffe, 0xe0dd) )
01707    {
01708       gdcmWarningMacro( "No sequence delimiter item at end of JPEG item sequence");
01709    }
01710 }
01711 
01725 bool File::ReadTag(uint16_t testGroup, uint16_t testElem)
01726 {
01727    long positionOnEntry = Fp->tellg();
01728    long currentPosition = Fp->tellg();          // On debugging purposes
01729 
01730    // Read the Item Tag group and element, and make
01731    // sure they are what we expected:
01732    uint16_t itemTagGroup;
01733    uint16_t itemTagElem;
01734    try
01735    {
01736       itemTagGroup = ReadInt16();
01737       itemTagElem  = ReadInt16();
01738    }
01739    catch ( FormatError )
01740    {
01741       gdcmErrorMacro( "Can not read tag for "
01742        << "   We should have found tag ("
01743        << DictEntry::TranslateToKey(testGroup,testElem) << ")"
01744        ) ;
01745 
01746       return false;
01747    }
01748    if ( itemTagGroup != testGroup || itemTagElem != testElem )
01749    { 
01750        // in order not to pollute output we don't warn on 'delimitors'
01751       if (itemTagGroup != 0xfffe ||  testGroup != 0xfffe )
01752          gdcmWarningMacro( "Wrong Item Tag found:"
01753           << "   We should have found tag ("
01754           << DictEntry::TranslateToKey(testGroup,testElem) << ")" << std::endl
01755           << "   but instead we encountered tag ("
01756           << DictEntry::TranslateToKey(itemTagGroup,itemTagElem) << ")"
01757           << "  at address: " << "  0x(" << std::hex 
01758           << (unsigned int)currentPosition  << std::dec << ")" 
01759           ) ;
01760       Fp->seekg(positionOnEntry, std::ios::beg);
01761 
01762       return false;
01763    }
01764    return true;
01765 }
01766 
01781 uint32_t File::ReadTagLength(uint16_t testGroup, uint16_t testElem)
01782 {
01783 
01784    if ( !ReadTag(testGroup, testElem) )
01785    {
01786       // Avoid polutting output
01787       if ( testGroup != 0xfffe ) 
01788          gdcmErrorMacro( "ReadTag did not succeed for ("
01789                     << DictEntry::TranslateToKey(testGroup,testElem) 
01790                     << ")..." );
01791       return 0;
01792    }
01793                                                                                 
01795    long currentPosition = Fp->tellg();
01796    uint32_t itemLength  = ReadInt32();
01797    gdcmDebugMacro( "Basic Item Length is: " << itemLength 
01798         << "  at address: " << std::hex << (unsigned int)currentPosition);
01799    return itemLength;
01800 }
01801 
01806 void File::ReadEncapsulatedBasicOffsetTable()
01807 {
01809    uint32_t itemLength = ReadTagLength(0xfffe, 0xe000);
01810 
01811    // When present, read the basic offset table itself.
01812    // Notes: - since the presence of this basic offset table is optional
01813    //          we can't rely on it for the implementation, and we will simply
01814    //          trash it's content (when present).
01815    //        - still, when present, we could add some further checks on the
01816    //          lengths, but we won't bother with such fuses for the time being.
01817    if ( itemLength != 0 )
01818    {
01819       char *charBasicOffsetTableItemValue = new char[itemLength];
01820       Fp->read(charBasicOffsetTableItemValue, itemLength);
01821       unsigned int nbEntries = itemLength/4;
01822       assert( nbEntries*4 == itemLength); // Make sure this is a multiple
01823       BasicOffsetTableItemValue = new uint32_t[nbEntries];
01824 
01825       for (unsigned int i=0; i < nbEntries; i++ )
01826       {
01827          BasicOffsetTableItemValue[i] = *((uint32_t*)(&charBasicOffsetTableItemValue[4*i]));
01828 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
01829          uint32_t val = BasicOffsetTableItemValue[i];
01830          BasicOffsetTableItemValue[i] 
01831            = (  (val<<24)               | ((val<<8)  & 0x00ff0000) | 
01832               ( (val>>8)  & 0x0000ff00) |  (val>>24)               );
01833 #endif
01834          gdcmDebugMacro( "Read one length for: " << 
01835                           std::hex << BasicOffsetTableItemValue[i] );
01836       }
01837 
01838       delete[] charBasicOffsetTableItemValue;
01839    }
01840 }
01841 
01842 // These are the deprecated method that one day should be removed (after the next release)
01843 
01844 //#ifndef GDCM_LEGACY_REMOVE
01845 /*
01846  * \ brief   Loader. (DEPRECATED :  temporaryly kept not to break the API)
01847  * @ param   fileName file to be open for parsing
01848  * @ return false if file cannot be open or no swap info was found,
01849  *         or no tag was found.
01850  * @ deprecated Use the Load() [ + SetLoadMode() ] + SetFileName() functions instead
01851  */
01852  /*
01853 bool File::Load( std::string const &fileName ) 
01854 {
01855    GDCM_LEGACY_REPLACED_BODY(File::Load(std::string), "1.2",
01856                              File::Load());
01857    SetFileName( fileName );
01858    if ( ! this->Document::Load( ) )
01859       return false;
01860 
01861    return DoTheLoadingJob( );
01862 }
01863 */
01864 //#endif
01865 
01866 //-----------------------------------------------------------------------------
01867 // Print
01868 
01869 //-----------------------------------------------------------------------------
01870 } // end namespace gdcm

Generated on Fri Jan 20 10:14:25 2006 for gdcm by  doxygen 1.4.4