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: 2007/08/24 10:45:18 $
00007   Version:   $Revision: 1.335 $
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 #include "gdcmSQItem.h"
00100 
00101 #include <vector>
00102 #include <stdio.h>  //sscanf
00103 #include <stdlib.h> // for atoi
00104 
00105 namespace GDCM_NAME_SPACE
00106 {
00107 
00108 //-----------------------------------------------------------------------------
00109 // Constructor / Destructor
00110 
00114 File::File():
00115    Document()
00116 {
00117    RLEInfo  = new RLEFramesInfo;
00118    JPEGInfo = new JPEGFragmentsInfo;
00119    GrPixel  = 0x7fe0;  // to avoid further troubles
00120    NumPixel = 0x0010;
00121    BasicOffsetTableItemValue = 0;
00122    FourthDimensionLocation = TagKey(0,0);
00123 }
00124 
00125 
00129 File::~File()
00130 {
00131    if ( RLEInfo )
00132       delete RLEInfo;
00133    if ( JPEGInfo )
00134       delete JPEGInfo;
00135    delete[] BasicOffsetTableItemValue;
00136 }
00137 
00138 //-----------------------------------------------------------------------------
00139 // Public
00145 bool File::Load( ) 
00146 {
00147    if ( ! this->Document::Load( ) )
00148       return false;
00149 
00150     return DoTheLoadingJob( );   
00151 }
00152 
00158 bool File::DoTheLoadingJob( ) 
00159 {
00160    // for some ACR-NEMA images GrPixel, NumPixel is *not* 7fe0,0010
00161    // We may encounter the 'RETired' (0x0028, 0x0200) tag
00162    // (Image Location") . This entry contains the number of
00163    // the group that contains the pixel data (hence the "Pixel Data"
00164    // is found by indirection through the "Image Location").
00165    // Inside the group pointed by "Image Location" the searched element
00166    // is conventionally the element 0x0010 (when the norm is respected).
00167    // When the "Image Location" is missing we default to group 0x7fe0.
00168    // Note: this IS the right place for the code
00169  
00170    // Image Location
00171    const std::string &imgLocation = GetEntryString(0x0028, 0x0200);
00172    if ( imgLocation == GDCM_UNFOUND )
00173    {
00174       // default value
00175       GrPixel = 0x7fe0;
00176    }
00177    else
00178    {
00179       GrPixel = (uint16_t) atoi( imgLocation.c_str() );
00180    }   
00181 
00182    // sometimes Image Location value doesn't follow
00183    // the supposed processor endianness.
00184    // see gdcmData/cr172241.dcm
00185    if ( GrPixel == 0xe07f )
00186    {
00187       GrPixel = 0x7fe0;
00188    }
00189 
00190    if ( GrPixel != 0x7fe0 )
00191    {
00192       // This is a kludge for old dirty Philips imager.
00193       NumPixel = 0x1010;
00194    }
00195    else
00196    {
00197       NumPixel = 0x0010;
00198    }
00199 
00200    // Now, we know GrPixel and NumPixel.
00201    // Let's create a VirtualDictEntry to allow a further VR modification
00202    // and force VR to match with BitsAllocated.
00203    DocEntry *entry = GetDocEntry(GrPixel, NumPixel); 
00204    if ( entry != 0 )
00205    {
00206       // Compute the RLE or JPEG info
00207       OpenFile();
00208       const std::string &ts = GetTransferSyntax();
00209       Fp->seekg( entry->GetOffset(), std::ios::beg );
00210       if ( Global::GetTS()->IsRLELossless(ts) ) 
00211          ComputeRLEInfo();
00212       else if ( Global::GetTS()->IsJPEG(ts) )
00213          ComputeJPEGFragmentInfo();
00214       CloseFile();
00215 
00216       // Create a new DataEntry to change the DictEntry
00217       // The changed DictEntry will have 
00218       // - a correct PixelVR OB or OW)
00219       // - the name to "Pixel Data"
00220       
00221        //==>Take it easy!
00222        //==> Just change the VR !
00223 
00224 /* 
00225       DataEntry *oldEntry = dynamic_cast<DataEntry *>(entry);
00226       if (oldEntry)
00227       {
00228          VRKey PixelVR;
00229          // 8 bits allocated is a 'O Bytes' , as well as 24 (old ACR-NEMA RGB)
00230          // more than 8 (i.e 12, 16) is a 'O Words'
00231          if ( GetBitsAllocated() == 8 || GetBitsAllocated() == 24 ) 
00232             PixelVR = "OB";
00233          else
00234             PixelVR = "OW";
00235 
00236          // Change only made if usefull
00237          if ( PixelVR != oldEntry->GetVR() )
00238          {
00239             //DictEntry* newDict = DictEntry::New(GrPixel,NumPixel,
00240             //                                    PixelVR,"1","Pixel Data");
00241             //DataEntry *newEntry = DataEntry::New(newDict);
00242             //newDict->Delete();
00243             //newEntry->Copy(entry);
00244             //newEntry->SetBinArea(oldEntry->GetBinArea(),oldEntry->IsSelfArea());
00245             //oldEntry->SetSelfArea(false);
00246 
00247             //RemoveEntry(oldEntry);
00248             //AddEntry(newEntry);
00249             //newEntry->Delete();
00250          }
00251       }
00252 */
00253          VRKey PixelVR;
00254          // 8 bits allocated is a 'OB(ytes)' , as well as 24 (old ACR-NEMA RGB)
00255          // more than 8 (i.e 12, 16) is a 'OW(ords)'
00256          if ( GetBitsAllocated() == 8 || GetBitsAllocated() == 24 ) 
00257             PixelVR = "OB";
00258          else
00259             PixelVR = "OW";
00260          // Change only made if usefull
00261          if ( PixelVR != entry->GetVR() )
00262          { 
00263             entry->SetVR(PixelVR);  
00264          }         
00265    }
00266    return true;
00267 }
00268 
00277 bool File::IsReadable()
00278 {
00279    if ( !Document::IsReadable() )
00280    {
00281       return false;
00282    }
00283 
00284    const std::string &res = GetEntryString(0x0028, 0x0005);
00285    if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 )
00286    {
00287       gdcmWarningMacro("Wrong Image Dimensions" << res);
00288       return false; // Image Dimensions
00289    }
00290    bool b0028_0100 = true;
00291    if ( !GetDocEntry(0x0028, 0x0100) )
00292    {
00293       gdcmWarningMacro("Bits Allocated (0028|0100) not found"); 
00294       //return false; // "Bits Allocated"
00295       b0028_0100 = false;
00296    }
00297    bool b0028_0101 = true;
00298    if ( !GetDocEntry(0x0028, 0x0101) )
00299    {
00300       gdcmWarningMacro("Bits Stored (0028|0101) not found");
00301       //return false; // "Bits Stored"
00302       b0028_0101 = false;
00303    }
00304    bool b0028_0102 = true;
00305    if ( !GetDocEntry(0x0028, 0x0102) )
00306    {
00307       gdcmWarningMacro("Hight Bit (0028|0102) not found"); 
00308       //return false; // "High Bit"
00309       b0028_0102 = false;
00310    }
00311    bool b0028_0103 = true;
00312    if ( !GetDocEntry(0x0028, 0x0103) )
00313    {
00314       gdcmWarningMacro("Pixel Representation (0028|0103) not found");
00315       //return false; // "Pixel Representation" i.e. 'Sign' ( 0 : unsigned, 1 : signed)
00316       b0028_0103 = false;
00317    }
00318 
00319    if ( !b0028_0100 && !b0028_0101 && !b0028_0102 && !b0028_0103)
00320    {
00321       gdcmWarningMacro("Too much mandatory Tags missing !");
00322       return false;
00323    }
00324 
00325    if ( !GetDocEntry(GrPixel, NumPixel) )
00326    {
00327       gdcmWarningMacro("Pixel Dicom Element " << std::hex <<
00328                         GrPixel << "|" << NumPixel << "not found");
00329       return false; // Pixel Dicom Element not found :-(
00330    }
00331    return true;
00332 }
00333 
00338 int File::GetImageNumber()
00339 {
00340    //0020 0013 : Image Number
00341    std::string strImNumber = GetEntryString(0x0020,0x0013);
00342    if ( strImNumber != GDCM_UNFOUND )
00343    {
00344       return atoi( strImNumber.c_str() );
00345    }
00346    return 0;   //Hopeless
00347 }
00348 
00353 ModalityType File::GetModality()
00354 {
00355    // 0008 0060 : Modality
00356    std::string strModality = GetEntryString(0x0008,0x0060);
00357    if ( strModality != GDCM_UNFOUND )
00358    {
00359            if ( strModality.find("AU")  < strModality.length()) return AU;
00360       else if ( strModality.find("AS")  < strModality.length()) return AS;
00361       else if ( strModality.find("BI")  < strModality.length()) return BI;
00362       else if ( strModality.find("CF")  < strModality.length()) return CF;
00363       else if ( strModality.find("CP")  < strModality.length()) return CP;
00364       else if ( strModality.find("CR")  < strModality.length()) return CR;
00365       else if ( strModality.find("CT")  < strModality.length()) return CT;
00366       else if ( strModality.find("CS")  < strModality.length()) return CS;
00367       else if ( strModality.find("DD")  < strModality.length()) return DD;
00368       else if ( strModality.find("DF")  < strModality.length()) return DF;
00369       else if ( strModality.find("DG")  < strModality.length()) return DG;
00370       else if ( strModality.find("DM")  < strModality.length()) return DM;
00371       else if ( strModality.find("DS")  < strModality.length()) return DS;
00372       else if ( strModality.find("DX")  < strModality.length()) return DX;
00373       else if ( strModality.find("ECG") < strModality.length()) return ECG;
00374       else if ( strModality.find("EPS") < strModality.length()) return EPS;
00375       else if ( strModality.find("FA")  < strModality.length()) return FA;
00376       else if ( strModality.find("FS")  < strModality.length()) return FS;
00377       else if ( strModality.find("HC")  < strModality.length()) return HC;
00378       else if ( strModality.find("HD")  < strModality.length()) return HD;
00379       else if ( strModality.find("LP")  < strModality.length()) return LP;
00380       else if ( strModality.find("LS")  < strModality.length()) return LS;
00381       else if ( strModality.find("MA")  < strModality.length()) return MA;
00382       else if ( strModality.find("MR")  < strModality.length()) return MR;
00383       else if ( strModality.find("NM")  < strModality.length()) return NM;
00384       else if ( strModality.find("OT")  < strModality.length()) return OT;
00385       else if ( strModality.find("PT")  < strModality.length()) return PT;
00386       else if ( strModality.find("RF")  < strModality.length()) return RF;
00387       else if ( strModality.find("RG")  < strModality.length()) return RG;
00388       else if ( strModality.find("RTDOSE")   
00389                                         < strModality.length()) return RTDOSE;
00390       else if ( strModality.find("RTIMAGE")  
00391                                         < strModality.length()) return RTIMAGE;
00392       else if ( strModality.find("RTPLAN")
00393                                         < strModality.length()) return RTPLAN;
00394       else if ( strModality.find("RTSTRUCT") 
00395                                         < strModality.length()) return RTSTRUCT;
00396       else if ( strModality.find("SM")  < strModality.length()) return SM;
00397       else if ( strModality.find("ST")  < strModality.length()) return ST;
00398       else if ( strModality.find("TG")  < strModality.length()) return TG;
00399       else if ( strModality.find("US")  < strModality.length()) return US;
00400       else if ( strModality.find("VF")  < strModality.length()) return VF;
00401       else if ( strModality.find("XA")  < strModality.length()) return XA;
00402       else if ( strModality.find("XC")  < strModality.length()) return XC;
00403 
00404       else
00405       {
00408          return Unknow;
00409       }
00410    }
00411    return Unknow;
00412 }
00413 
00419 int File::GetXSize()
00420 {
00421    DataEntry *entry = GetDataEntry(0x0028,0x0011);
00422    if( entry )
00423       return (int)entry->GetValue(0);
00424    return 0;
00425 }
00426 
00433 int File::GetYSize()
00434 {
00435    DataEntry *entry = GetDataEntry(0x0028,0x0010);
00436    if( entry )
00437       return (int)entry->GetValue(0);
00438 
00439    if ( IsDicomV3() )
00440    {
00441       return 0;
00442    }
00443 
00444    // The Rows (0028,0010) entry was optional for ACR/NEMA.
00445    // (at least some images didn't have it.)
00446    // It might hence be a signal (1D image). So we default to 1:
00447    return 1;
00448 }
00449 
00458 int File::GetZSize()
00459 {
00460    // Both  DicomV3 and ACR/Nema consider the "Number of Frames"
00461    // as the third dimension.
00462    DataEntry *entry = GetDataEntry(0x0028,0x0008);
00463    if( entry )
00464       return (int)entry->GetValue(0);
00465 
00466    // We then consider the "Planes" entry as the third dimension 
00467    entry = GetDataEntry(0x0028,0x0012);
00468    if( entry )
00469       return (int)entry->GetValue(0);
00470    return 1;
00471 }
00472 
00473 // Special case:
00474 //  ts["1.2.840.10008.5.1.4.1.1.4.1"] = "Enhanced MR Image Storage";
00475 bool File::GetSpacing(float &xspacing, float &yspacing, float &zspacing)
00476 {
00477       xspacing = yspacing = zspacing = 1.0;
00478       TS *ts = Global::GetTS();
00479       std::string sopclassuid_used;
00480       // D 0002|0002 [UI] [Media Storage SOP Class UID]
00481  
00482       //const std::string &mediastoragesopclassuid_str = GetEntryValue(0x0002,0x0002);  
00483       const std::string &mediastoragesopclassuid_str = GetEntryString(0x0002,0x0002);
00484       const std::string &mediastoragesopclassuid = ts->GetValue(mediastoragesopclassuid_str);
00485       //D 0008|0016 [UI] [SOP Class UID]
00486       const std::string &sopclassuid_str = GetEntryString(0x0008,0x0016);
00487       const std::string &sopclassuid = ts->GetValue(sopclassuid_str);
00488       if ( mediastoragesopclassuid == GDCM_UNFOUND && sopclassuid == GDCM_UNFOUND )
00489         {
00490         return false;
00491         }
00492       else
00493         {
00494         if( mediastoragesopclassuid == sopclassuid )
00495           {
00496           sopclassuid_used = mediastoragesopclassuid;
00497           }
00498         else
00499           {
00500           gdcmWarningMacro( "Inconsistant SOP Class UID: "
00501             << mediastoragesopclassuid << " and " << sopclassuid );
00502           return false;
00503           }
00504         }
00505       // ok we have now the correc SOP Class UID
00506       if( sopclassuid_used == "Enhanced MR Image Storage" )
00507         {
00508         SeqEntry *PerframeFunctionalGroupsSequence = GetSeqEntry(0x5200,0x9230);
00509         unsigned int n = PerframeFunctionalGroupsSequence->GetNumberOfSQItems();
00510         if( !n ) return false;
00511         SQItem *item1 = PerframeFunctionalGroupsSequence->GetFirstSQItem();
00512         DocEntry *p = item1->GetDocEntry(0x0028,0x9110);
00513         if( !p ) return false;
00514         SeqEntry *seq = dynamic_cast<SeqEntry*>(p);
00515         unsigned int n1 = seq->GetNumberOfSQItems();
00516         if( !n1 ) return false;
00517         SQItem *item2 = seq->GetFirstSQItem();
00518         // D 0028|0030 [DS] [Pixel Spacing] [0.83333331346511\0.83333331346511 ]
00519         DocEntry *p2 = item2->GetDocEntry(0x0028,0x0030);
00520         if( !p2 ) return false;
00521         DataEntry *entry = dynamic_cast<DataEntry *>(p2);
00522         std::string spacing = entry->GetString();
00523         if ( sscanf( spacing.c_str(), "%f\\%f", &yspacing, &xspacing) != 2 )
00524           {
00525           xspacing = yspacing = 1.;
00526           return false;
00527           }
00528         // D 0018|0050 [DS] [Slice Thickness] [1 ]
00529         DocEntry *p3 = item2->GetDocEntry(0x0018,0x0050);
00530         if( !p3 ) return false;
00531         DataEntry *entry2 = dynamic_cast<DataEntry *>(p3);
00532         std::string thickness = entry2->GetString();
00533         if ( sscanf( thickness.c_str(), "%f", &zspacing) != 1 )
00534           {
00535           zspacing = 1.;
00536           return false;
00537           }
00538         return true;
00539         }
00540      return false;
00541    }
00542 
00551 int File::GetTSize()
00552 {
00553    if (FourthDimensionLocation == TagKey(0,0) )// 4D location is not set : not a 4D object
00554       return 1;
00555       
00556    DataEntry *entry = GetDataEntry(FourthDimensionLocation.GetGroup(),
00557                                    FourthDimensionLocation.GetElement() );
00558    if( !entry )
00559    {
00560       gdcmWarningMacro( " FourthDimensionLocation not found at : " <<
00561                     std::hex << FourthDimensionLocation.GetGroup()
00562                   << "|" << FourthDimensionLocation.GetElement());
00563       return 1;
00564    }
00565    else
00566    {
00567       return (int)entry->GetValue(0);
00568    }      
00569 }
00570 
00571 
00572 
00579 float File::GetXSpacing()
00580 {
00581    float xspacing = 1.0;
00582    float yspacing = 1.0;
00583    float zspacing = 1.0;
00584 
00585    uint32_t nbValue;
00586    DataEntry *entry;
00587    bool ok = false; 
00588   if ( GetSpacing(xspacing,yspacing,zspacing) )
00589   {
00590     return xspacing;
00591   }
00592  // else fallback
00593 
00594 /*
00595 From:David Clunie - view profile
00596 Date:Wed, May 24 2006 1:12 pm
00597 Email:David Clunie <dclu...@dclunie.com>
00598 Groups:comp.protocols.dicom
00599 
00600 The short answer is that:
00601 
00602 - (0018,1164) describes a spacing equivalent to that which
00603   would be measured off a film in projection radiography
00604 
00605 - (0018,7022) does not describe the image pixels themselves,
00606   since detector elements may have been binned to produce
00607   pixels
00608 
00609 - (0018,7020) may be different from (0018,7022) since there
00610   may be non-sensitive material separating individual
00611   detectors (i.e. the size is smaller than the spacing
00612   between centers)
00613 
00614 Only (0018,1164) is relevant when measuring things; the
00615 detector-specific attributes are there to describe the
00616 acquisition.
00617 
00618 David
00619 
00620 PS. For ultrasound you need to use Region Calibration. 
00621 */
00622  
00623 /*   
00624 It *SHOULD* first find the IOD and then deduce which tags to read
00625 Eg: Cross section this is in Pixel Spacing (0028,0030)
00626 CR is in Imager Pixel Spacing (0018,1164)
00627 US is in Pixel Aspect Ratio (0028,0034)
00628 RT is in :
00629 (3002,0011) Image Plane Pixel Spacing
00630 (3002,0012) RT Image Position
00631 and
00632 (3004,000c) for deducing Z spacing 
00633 */
00634 
00635    std::string SOPClassUID = GetEntryString(0x0008,0x0016);
00636 
00639    
00641            
00642    if (Util::DicomStringEqual( SOPClassUID,"1.2.840.10008.5.1.4.1.1.6")
00643    // Ultrasound Image Storage (Retired)
00644     || Util::DicomStringEqual( SOPClassUID,"1.2.840.10008.5.1.4.1.1.6.1")
00645    // Ultrasound Image Storage
00646     || Util::DicomStringEqual( SOPClassUID,"1.2.840.10008.5.1.4.1.1.3")
00647    // Ultrasound Multi-Frame Storage (Retired)
00648     || Util::DicomStringEqual( SOPClassUID,"1.2.840.10008.5.1.4.1.1.3.1") )
00649    // Ultrasound Multi-FrameImage Storage
00650    {
00651       // - check if  SOPClassUID contains 2 parts (e.g. "4\3")
00652       // - guess how to deduce the spacing (FOV ?, ??)
00653       
00654       entry = GetDataEntry(0x0028,0x0034);
00655       if ( entry )
00656       {
00657          nbValue = entry->GetValueCount();
00658          if( nbValue !=2 ) {
00659             gdcmWarningMacro("PixelAspectRatio (0x0028,0x0034) "
00660             << "has a wrong number of values :" << nbValue);
00661          }
00662          xspacing = 1.0; // We get Pixel Aspect Ratio, not Spacing ...
00663          ok = true;
00664       }
00665   
00666       if (ok)
00667          return xspacing;
00668    }
00669 /*      
00670    if (Util::DicomStringEqual( SOPClassUID,"1.2.840.10008.5.1.4.1.1.1") ) 
00671    // Computed Radiography Image Storage   
00672 
00673    // CR is in Imager Pixel Spacing (0018,1164)//    
00674 
00675 */
00676    // go on with old method ...
00677    // ---------------------
00678    // To follow David Clunie's advice, we first check ImagerPixelSpacing
00679 
00680    entry = GetDataEntry(0x0018,0x1164);
00681    if( entry )
00682    {
00683       nbValue = entry->GetValueCount();
00684       // Can't use IsValueCountValid because of the complex heuristic.
00685       if( nbValue !=2 )
00686          gdcmWarningMacro("ImagerPixelSpacing (0x0018,0x1164) "
00687          << "has a wrong number of values :" << nbValue);
00688 
00689       if( nbValue >= 3 )
00690          xspacing = (float)entry->GetValue(2);
00691       else if( nbValue >= 2 )
00692          xspacing = (float)entry->GetValue(1);
00693       else
00694          xspacing = (float)entry->GetValue(0);
00695 
00696       if ( xspacing == 0.0 )
00697          xspacing = 1.0;
00698       return xspacing;
00699    }
00700    else
00701    {
00702       gdcmWarningMacro( "Unfound Imager Pixel Spacing (0018,1164)" );
00703    }
00704 
00705    entry = GetDataEntry(0x0028,0x0030);
00706    if( entry )
00707    {
00708       nbValue = entry->GetValueCount();
00709       if( nbValue !=2 )
00710          gdcmWarningMacro("PixelSpacing (0x0018,0x0030) "
00711           << "has a wrong number of values :" << nbValue);      
00712   
00713       if( nbValue >= 3 )
00714          xspacing = (float)entry->GetValue(2);
00715       else if( nbValue >= 2 )
00716          xspacing = (float)entry->GetValue(1);
00717       else
00718          xspacing = (float)entry->GetValue(0);
00719 
00720       if ( xspacing == 0.0 )
00721          xspacing = 1.0;
00722       return xspacing;
00723    }
00724    else
00725    {
00726       gdcmWarningMacro( "Unfound Pixel Spacing (0028,0030)" );
00727    }
00728    return xspacing;
00729 }
00730 
00737 float File::GetYSpacing()
00738 {
00739    float xspacing = 1., yspacing = 1.0, zspacing = 1.;
00740    uint32_t nbValue;
00741    DataEntry *entry;
00742    bool ok = false;
00743   if ( GetSpacing(xspacing,yspacing,zspacing) )
00744   {
00745     return yspacing;
00746   }
00747  // else fallback
00748 
00749    std::string SOPClassUID = GetEntryString(0x0008,0x0016);
00750 
00753    
00755 
00756    if (Util::DicomStringEqual( SOPClassUID,"1.2.840.10008.5.1.4.1.1.6")
00757    // Ultrasound Image Storage (Retired)
00758     || Util::DicomStringEqual( SOPClassUID,"1.2.840.10008.5.1.4.1.1.6.1")
00759    // Ultrasound Image Storage
00760     || Util::DicomStringEqual( SOPClassUID,"1.2.840.10008.5.1.4.1.1.3")
00761    // Ultrasound Multi-Frame Storage (Retired)
00762     || Util::DicomStringEqual( SOPClassUID,"1.2.840.10008.5.1.4.1.1.3.1") )
00763    // Ultrasound Multi-FrameImage Storage      
00764    {
00765       // - check if  SOPClassUID contains 2 parts (e.g. "4\3")
00766       // - no way to deduce the spacing/
00767       
00768       entry = GetDataEntry(0x0028,0x0034);
00769       if ( entry )
00770       {       
00771          nbValue = entry->GetValueCount();
00772          if( nbValue ==2 ) {
00773             yspacing = (float)entry->GetValue(0)/(float)entry->GetValue(1);
00774             //std::cout << "ys " << yspacing << std::endl;
00775             ok = true;
00776       }
00777       else
00778       {
00779          gdcmWarningMacro("PixelAspectRatio (0x0028,0x0034) "
00780                << "has a wrong number of values :" << nbValue);
00781          if (nbValue == 0 ) {
00782             ok = false;
00783          }
00784          else if (nbValue == 1 ) {
00785             yspacing = 1.0; // We get Pixel Aspect Ratio, not Spacing ...
00786             ok = true;
00787          } 
00788       }                  
00789    }
00790   
00791       if (ok)
00792          return yspacing;      
00793    }   
00794 
00795    // go on with old method ...
00796    // ---------------------
00797    // To follow David Clunie's advice, we first check ImagerPixelSpacing
00798    yspacing = 1.0;
00799    // To follow David Clunie's advice, we first check ImagerPixelSpacing
00800 
00801    entry = GetDataEntry(0x0018,0x1164);
00802    if( entry )
00803    {
00804       yspacing = (float)entry->GetValue(0);
00805 
00806       if ( yspacing == 0.0 )
00807          yspacing = 1.0;
00808       return yspacing;
00809    }
00810    else
00811    {
00812       gdcmWarningMacro( "Unfound Imager Pixel Spacing (0018,1164)" );
00813    }
00814 
00815    entry = GetDataEntry(0x0028,0x0030);
00816    if( entry )
00817    {
00818       yspacing = (float)entry->GetValue(0);
00819 
00820       if ( yspacing == 0.0 )
00821          yspacing = 1.0;
00822       return yspacing;
00823    }
00824    else
00825    {
00826       gdcmWarningMacro( "Unfound Pixel Spacing (0028,0030)" );
00827    }
00828 
00829    return yspacing;
00830 } 
00831 
00845 float File::GetZSpacing()
00846 {
00847 
00848    float xspacing = 1.0;
00849    float yspacing = 1.0;
00850    float zspacing = 1.0;
00851    if ( GetSpacing(xspacing,yspacing,zspacing) )
00852    {
00853       return zspacing;
00854    }
00855 
00856    // Spacing Between Slices : distance between the middle of 2 slices
00857    // Slices may be :
00858    //   jointives     (Spacing between Slices = Slice Thickness)
00859    //   overlapping   (Spacing between Slices < Slice Thickness)
00860    //   disjointes    (Spacing between Slices > Slice Thickness)
00861    // Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal
00862    //   It only concerns the MRI guys, not people wanting to visualize volumes
00863    //   If Spacing Between Slices is missing, 
00864    //   we suppose slices joint together
00865    DataEntry *entry = GetDataEntry(0x0018,0x0088);
00866    if( entry )
00867    {      zspacing = (float)entry->GetValue(0);
00868 
00869       if ( zspacing == 0.0 )
00870          zspacing = 1.0;
00871       return zspacing;
00872    }
00873    else
00874       gdcmWarningMacro("Unfound Spacing Between Slices (0018,0088)");
00875 
00876    // if no 'Spacing Between Slices' is found, 
00877    // we assume slices join together
00878    // (no overlapping, no interslice gap)
00879    entry = GetDataEntry(0x0018,0x0050);
00880    if( entry )
00881    {
00882       zspacing = (float)entry->GetValue(0);
00883 
00884       if ( zspacing == 0.0 )
00885          zspacing = 1.0;
00886       return zspacing;
00887    }
00888    else
00889       gdcmWarningMacro("Unfound Slice Thickness (0018,0050)");
00890 
00891    // if no 'Spacing Between Slices' is found, 
00892    // we assume slices join together
00893    // (no overlapping, no interslice gap)
00894    entry = GetDataEntry(0x3004,0x000c);
00895    if( entry )
00896    {
00897       float z1 = (float)entry->GetValue(0);
00898       float z2 = (float)entry->GetValue(1);
00899       zspacing = z2 - z1; // can be negative...
00900 
00901       if ( zspacing == 0.0 )
00902          zspacing = 1.0;
00903       return zspacing;
00904    }
00905 
00906    return zspacing;
00907 }
00908 
00915 float File::GetXOrigin()
00916 {
00917    DataEntry *entry = GetDataEntry(0x0020,0x0032);
00918    if( !entry )
00919    {
00920       gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
00921       entry = GetDataEntry(0x0020,0x0030);
00922       if( !entry )
00923       {
00924          gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
00925          return 0.0f;
00926       }
00927    }
00928 
00929    if( entry->GetValueCount() == 3 )
00930    {
00931       if (!entry->IsValueCountValid() )
00932       {
00933          gdcmErrorMacro( "Invalid Value Count" );
00934       }
00935       return (float)entry->GetValue(0);
00936    }
00937    return 0.0f;
00938 }
00939 
00946 float File::GetYOrigin()
00947 {
00948    DataEntry *entry = GetDataEntry(0x0020,0x0032);
00949    if( !entry )
00950    {
00951       gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
00952       entry = GetDataEntry(0x0020,0x0030);
00953       if( !entry )
00954       {
00955          gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
00956          return 0.0f;
00957       }
00958    }
00959 
00960    if( entry->GetValueCount() == 3 )
00961    {
00962       if (!entry->IsValueCountValid() )
00963       {
00964          gdcmErrorMacro( "Invalid Value Count" );
00965       }
00966       return (float)entry->GetValue(1);
00967    }
00968    return 0.0f;
00969 }
00970 
00979 float File::GetZOrigin()
00980 {
00981    DataEntry *entry = GetDataEntry(0x0020,0x0032);
00982    if( entry )
00983    {
00984       if( entry->GetValueCount() == 3 )
00985       {
00986          if (!entry->IsValueCountValid() )
00987          {
00988             gdcmErrorMacro( "Invalid Value Count" );
00989          }
00990          return (float)entry->GetValue(2);
00991       }
00992       gdcmWarningMacro( "Wrong Image Position Patient (0020,0032)");
00993       return 0.0f;
00994    }
00995 
00996    entry = GetDataEntry(0x0020,0x0030);
00997    if( entry )
00998    {
00999       if( entry->GetValueCount() == 3 )
01000       {
01001          if (!entry->IsValueCountValid() )
01002          {
01003             gdcmErrorMacro( "Invalid Value Count" );
01004          }
01005          return (float)entry->GetValue(2);
01006       }
01007       gdcmWarningMacro( "Wrong Image Position (RET) (0020,0030)");
01008       return 0.0f;
01009    }
01010 
01011    // for *very* old ACR-NEMA images
01012    entry = GetDataEntry(0x0020,0x1041);
01013    if( entry )
01014    {
01015       if( entry->GetValueCount() == 1 )
01016       {
01017          if (!entry->IsValueCountValid() )
01018          {
01019             gdcmErrorMacro( "Invalid Value Count" );
01020          }
01021          return (float)entry->GetValue(0); // VM=1 !
01022       }
01023       gdcmWarningMacro( "Wrong Slice Location (0020,1041)");
01024       return 0.0f;
01025    }
01026 
01027    entry = GetDataEntry(0x0020,0x0050);
01028    if( entry )
01029    {
01030       if( entry->GetValueCount() == 1 )
01031       {
01032          if (!entry->IsValueCountValid() )
01033          {
01034             gdcmErrorMacro( "Invalid Value Count" );
01035          }
01036          return (float)entry->GetValue(0);
01037       }
01038       gdcmWarningMacro( "Wrong Location (0020,0050)");
01039       return 0.0f;
01040    }
01041    return 0.; // Hopeless
01042 }
01043 
01056 bool File::GetImageOrientationPatient( float iop[6] )
01057 {
01058    std::string strImOriPat;
01059    //iop is supposed to be float[6]
01060    iop[0] = iop[4] = 1.;
01061    iop[1] = iop[2] = iop[3] = iop[5] = 0.;
01062 
01063    // 0020 0037 DS REL Image Orientation (Patient)
01064    if ( (strImOriPat = GetEntryString(0x0020,0x0037)) != GDCM_UNFOUND )
01065    {
01066       if ( sscanf( strImOriPat.c_str(), "%f \\ %f \\%f \\%f \\%f \\%f ", 
01067           &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 )
01068       {
01069          gdcmWarningMacro( "Wrong Image Orientation Patient (0020,0037)."
01070                         << " Less than 6 values were found." );
01071          return false;
01072       }
01073       return true;
01074    }
01075    //For ACR-NEMA
01076    // 0020 0035 DS REL Image Orientation (RET)
01077    else if ( (strImOriPat = GetEntryString(0x0020,0x0035)) != GDCM_UNFOUND )
01078    {
01079       if ( sscanf( strImOriPat.c_str(), "%f \\ %f \\%f \\%f \\%f \\%f ", 
01080           &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 )
01081       {
01082          gdcmWarningMacro( "wrong Image Orientation Patient (0020,0035). "
01083                         << "Less than 6 values were found." );
01084          return false;
01085       }
01086       return true;
01087    }
01088    return false;
01089 }
01090 
01096 float File::GetXCosineOnX()
01097 {  
01098    float iop[6];
01099    GetImageOrientationPatient( iop );
01100    return(iop[0]);
01101 }
01102    
01108 float File::GetXCosineOnY()
01109 {  
01110    float iop[6];
01111    GetImageOrientationPatient( iop );
01112    return(iop[1]);
01113 }   
01114 
01120 float File::GetXCosineOnZ()
01121 {  
01122    float iop[6];
01123    GetImageOrientationPatient( iop );
01124    return(iop[2]);
01125 }   
01126 
01132 float File::GetYCosineOnX()
01133 {  
01134    float iop[6];
01135    GetImageOrientationPatient( iop );
01136    return(iop[3]);
01137 }
01138    
01144 float File::GetYCosineOnY()
01145 {  
01146    float iop[6];
01147    GetImageOrientationPatient( iop );
01148    return(iop[4]);
01149 }   
01150 
01156 float File::GetYCosineOnZ()
01157 {  
01158    float iop[6];
01159    GetImageOrientationPatient( iop );
01160    return(iop[5]);
01161 }    
01172 bool File::GetImagePositionPatient( float ipp[3] )
01173 {
01174    std::string strImPosiPat;
01175    //ipp is supposed to be float[3]
01176    ipp[0] = ipp[1] = ipp[2] = 0.;
01177 
01178    // 0020 0032 DS REL Image Position (Patient)
01179    strImPosiPat = GetEntryString(0x0020,0x0032);
01180    if ( strImPosiPat != GDCM_UNFOUND )
01181    {
01182       if ( sscanf( strImPosiPat.c_str(), "%f \\ %f \\%f ", 
01183           &ipp[0], &ipp[1], &ipp[2]) != 3 )
01184       {
01185          gdcmWarningMacro( "Wrong Image Position Patient (0020,0032)."
01186                         << " Less than 3 values were found." );
01187          return false;
01188       }
01189       return true;
01190    }
01191    //For ACR-NEMA
01192    // 0020 0030 DS REL Image Position (RET)
01193    else if ( (strImPosiPat = GetEntryString(0x0020,0x0030)) != GDCM_UNFOUND )
01194    {
01195       if ( sscanf( strImPosiPat.c_str(), "%f \\ %f \\%f ", 
01196           &ipp[0], &ipp[1], &ipp[2]) != 3 )
01197       {
01198          gdcmWarningMacro( "wrong Image Position Patient (0020,0030). "
01199                         << "Less than 3 values were found." );
01200          return false;
01201       }
01202       return true;
01203    }
01204    return false;
01205 }
01206 
01213 int File::GetBitsStored()
01214 {
01215    DataEntry *entry = GetDataEntry(0x0028,0x0101);
01216    if( !entry )
01217    {
01218       gdcmWarningMacro("BitsStored (0028,0101) is supposed to be mandatory");
01219       return 0;
01220    }
01221    return (int)entry->GetValue(0);
01222 }
01223 
01230 int File::GetBitsAllocated()
01231 {
01232    DataEntry *entry = GetDataEntry(0x0028,0x0100);
01233    if( !entry )
01234    {
01235       gdcmWarningMacro("BitsAllocated (0028,0100) is supposed to be mandatory");
01236       return 0;
01237    }
01238    return (int)entry->GetValue(0);
01239 }
01240 
01247 int File::GetHighBitPosition()
01248 {
01249    DataEntry *entry = GetDataEntry(0x0028,0x0102);
01250    if( !entry )
01251    {
01252       gdcmWarningMacro("HighBitPosition (0028,0102) is supposed to be mandatory");
01253       return 0;
01254    }
01255    return (int)entry->GetValue(0);
01256 }
01257 
01264 int File::GetSamplesPerPixel()
01265 {
01266    DataEntry *entry = GetDataEntry(0x0028,0x0002);
01267    if( !entry )
01268    {
01269       gdcmWarningMacro("SamplesPerPixel (0028,0002) is supposed to be mandatory");
01270       return 1; // Well, it's supposed to be mandatory ...
01271                 // but sometimes it's missing : *we* assume Gray pixels
01272    }
01273    return (int)entry->GetValue(0);
01274 }
01275 
01281 int File::GetPlanarConfiguration()
01282 {
01283    DataEntry *entry = GetDataEntry(0x0028,0x0006);
01284    if( !entry )
01285    {
01286       return 0;
01287    }
01288    return (int)entry->GetValue(0);
01289 }
01290 
01296 int File::GetPixelSize()
01297 {
01298    // 0028 0100 US IMG Bits Allocated
01299    // (in order no to be messed up by old ACR-NEMA RGB images)
01300    assert( !(GetEntryString(0x0028,0x0100) == "24") );
01301 
01302    std::string pixelType = GetPixelType();
01303    if ( pixelType ==  "8U" || pixelType == "8S" )
01304    {
01305       return 1;
01306    }
01307    if ( pixelType == "16U" || pixelType == "16S")
01308    {
01309       return 2;
01310    }
01311    if ( pixelType == "32U" || pixelType == "32S")
01312    {
01313       return 4;
01314    }
01315    if ( pixelType == "FD" )
01316    {
01317       return 8;
01318    }
01319    gdcmWarningMacro( "Unknown pixel type: " << pixelType);
01320    return 0;
01321 }
01322 
01338 std::string File::GetPixelType()
01339 {
01340    std::string bitsAlloc = GetEntryString(0x0028, 0x0100); // Bits Allocated
01341    if ( bitsAlloc == GDCM_UNFOUND )
01342    {
01343       gdcmWarningMacro( "Bits Allocated (0028,0100) supposed to be mandatory");
01344       bitsAlloc = "16"; // default and arbitrary value, not to polute the output
01345    }
01346 
01347    else if ( bitsAlloc == "64" )
01348    {
01349       return "FD";
01350    }
01351      // useless since we have to bypass a bug ( >8 && < 16)
01352    else if ( bitsAlloc == "12" )
01353    {
01354       // It will be unpacked
01355       bitsAlloc = "16";
01356    }
01357    
01358    else if ( bitsAlloc == "24" )
01359    {
01360       // (in order no to be messed up by old RGB images)
01361       bitsAlloc = "8";
01362    }
01363 
01364    int i= atoi(bitsAlloc.c_str());  // fix a bug in some headers
01365    if ( i > 8 &&  i < 16 )
01366    {
01367       bitsAlloc = "16";
01368    }
01369 
01370    std::string sign;
01371    if( IsSignedPixelData() )
01372    {
01373       sign = "S";
01374    }
01375    else
01376    {
01377       sign = "U";
01378    }
01379    return bitsAlloc + sign;
01380 }
01381 
01390 bool File::IsSignedPixelData()
01391 {
01392    DataEntry *entry = GetDataEntry(0x0028, 0x0103);//"Pixel Representation"
01393    if( !entry )
01394    {
01395       gdcmWarningMacro( "Pixel Representation (0028,0103) supposed to be "
01396                       << "mandatory");
01397       return false;
01398    }
01399    return entry->GetValue(0) != 0;
01400 }
01401 
01407 bool File::IsMonochrome()
01408 {
01409    const std::string &PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
01410    if (  Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1")
01411       || Util::DicomStringEqual(PhotometricInterp, "MONOCHROME2") )
01412    {
01413       return true;
01414    }
01415    if ( PhotometricInterp == GDCM_UNFOUND )
01416    {
01417       gdcmWarningMacro( "Photometric Interpretation (0028,0004) supposed to be "
01418                          << "mandatory");
01419       // to deal with old ACR-NEMA images
01420       if (GetNumberOfScalarComponents() == 1)
01421          return true;
01422    }
01423    return false;
01424 }
01425 
01431 bool File::IsMonochrome1()
01432 {
01433    const std::string &PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
01434    if (  Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1") )
01435    {
01436       return true;
01437    }
01438    if ( PhotometricInterp == GDCM_UNFOUND )
01439    {
01440       gdcmWarningMacro( "Photometric Interpretation (0028,0004) : supposed to"
01441       << " be mandatory! ");
01442    }
01443    return false;
01444 }
01445 
01451 bool File::IsPaletteColor()
01452 {
01453    std::string PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
01454    if (   PhotometricInterp == "PALETTE COLOR " )
01455    {
01456       return true;
01457    }
01458    if ( PhotometricInterp == GDCM_UNFOUND )
01459    {
01460       gdcmDebugMacro( "Not found : Palette color (0028,0004)");
01461    }
01462    return false;
01463 }
01464 
01470 bool File::IsYBRFull()
01471 {
01472    std::string PhotometricInterp = GetEntryString( 0x0028, 0x0004 );
01473    if (   PhotometricInterp == "YBR_FULL" )
01474    {
01475       return true;
01476    }
01477    if ( PhotometricInterp == GDCM_UNFOUND )
01478    {
01479       gdcmDebugMacro( "Not found : YBR Full (0028,0004)");
01480    }
01481    return false;
01482 }
01483 
01492 bool File::HasLUT()
01493 {
01494    // Check the presence of the LUT Descriptors, and LUT Tables    
01495    // LutDescriptorRed    
01496    if ( !GetDocEntry(0x0028,0x1101) )
01497    {
01498       return false;
01499    }
01500    // LutDescriptorGreen 
01501    if ( !GetDocEntry(0x0028,0x1102) )
01502    {
01503       return false;
01504    }
01505    // LutDescriptorBlue 
01506    if ( !GetDocEntry(0x0028,0x1103) )
01507    {
01508       return false;
01509    }
01510    // Red Palette Color Lookup Table Data
01511    if ( !GetDocEntry(0x0028,0x1201) )
01512    {
01513       return false;
01514    }
01515    // Green Palette Color Lookup Table Data       
01516    if ( !GetDocEntry(0x0028,0x1202) )
01517    {
01518       return false;
01519    }
01520    // Blue Palette Color Lookup Table Data      
01521    if ( !GetDocEntry(0x0028,0x1203) )
01522    {
01523       return false;
01524    }
01525 
01526    // FIXME : (0x0028,0x3006) : LUT Data (CTX dependent)
01527    //         NOT taken into account, but we don't know how to use it ...   
01528    return true;
01529 }
01530 
01538 int File::GetLUTNbits()
01539 {
01540    std::vector<std::string> tokens;
01541    int lutNbits;
01542 
01543    //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red
01544    //                                = Lookup Table Desc-Blue
01545    // Consistency already checked in GetLUTLength
01546    std::string lutDescription = GetEntryString(0x0028,0x1101);
01547    if ( lutDescription == GDCM_UNFOUND )
01548    {
01549       return 0;
01550    }
01551 
01552    tokens.clear(); // clean any previous value
01553    Util::Tokenize ( lutDescription, tokens, "\\" );
01554    //LutLength=atoi(tokens[0].c_str());
01555    //LutDepth=atoi(tokens[1].c_str());
01556 
01557    lutNbits = atoi( tokens[2].c_str() );
01558    tokens.clear();
01559 
01560    return lutNbits;
01561 }
01562 
01563 // Special case:
01564 //  ts["1.2.840.10008.5.1.4.1.1.4.1"] = "Enhanced MR Image Storage";
01565    bool File::GetRescaleSlopeIntercept(double &slope, double &intercept)
01566    {
01567       slope = 1.0;
01568       intercept = 0.0;
01569       TS *ts = Global::GetTS();
01570       std::string sopclassuid_used;
01571       // D 0002|0002 [UI] [Media Storage SOP Class UID]
01572       const std::string &mediastoragesopclassuid_str = GetEntryString(0x0002,0x0002);
01573       const std::string &mediastoragesopclassuid = ts->GetValue(mediastoragesopclassuid_str);
01574       //D 0008|0016 [UI] [SOP Class UID]
01575       const std::string &sopclassuid_str = GetEntryString(0x0008,0x0016);
01576       const std::string &sopclassuid = ts->GetValue(sopclassuid_str);
01577       if ( mediastoragesopclassuid == GDCM_UNFOUND && sopclassuid == GDCM_UNFOUND )
01578         {
01579         return false;
01580         }
01581       else
01582         {
01583         if( mediastoragesopclassuid == sopclassuid )
01584           {
01585           sopclassuid_used = mediastoragesopclassuid;
01586           }
01587         else
01588           {
01589           gdcmWarningMacro( "Inconsistant SOP Class UID: "
01590             << mediastoragesopclassuid << " and " << sopclassuid );
01591           return false;
01592           }
01593         }
01594       // ok we have now the correc SOP Class UID
01595       if( sopclassuid_used == "Enhanced MR Image Storage" )
01596         {
01597         SeqEntry *PerframeFunctionalGroupsSequence = GetSeqEntry(0x5200,0x9230);
01598         unsigned int n = PerframeFunctionalGroupsSequence->GetNumberOfSQItems();
01599         if( !n ) return false;
01600         SQItem *item1 = PerframeFunctionalGroupsSequence->GetFirstSQItem();
01601         DocEntry *p = item1->GetDocEntry(0x0028,0x9145);
01602         if( !p ) return false;
01603         SeqEntry *seq = dynamic_cast<SeqEntry*>(p);
01604         unsigned int n1 = seq->GetNumberOfSQItems();
01605         if( !n1 ) return false;
01606         SQItem *item2 = seq->GetFirstSQItem();
01607         // D 0028|1052 [DS] [Rescale Intercept] [0 ]
01608         DocEntry *p2 = item2->GetDocEntry(0x0028,0x1052);
01609         if( !p2 ) return false;
01610         DataEntry *entry = dynamic_cast<DataEntry *>(p2);
01611         std::string intercept_str = entry->GetString();
01612         if ( sscanf( intercept_str.c_str(), "%lf", &intercept) != 1 )
01613           {
01614           intercept = 0.;
01615           return false;
01616           }
01617         // D 0028|1053 [DS] [Rescale Slope] [5.65470085470085]
01618         DocEntry *p3 = item2->GetDocEntry(0x0028,0x1053);
01619         if( !p3 ) return false;
01620         DataEntry *entry2 = dynamic_cast<DataEntry *>(p3);
01621         std::string slope_str = entry2->GetString();
01622         if ( sscanf( slope_str.c_str(), "%lf", &slope) != 1 )
01623           {
01624           slope = 1.;
01625           return false;
01626           }
01627         return true;
01628         }
01629      return false;
01630    }
01631 
01636 double File::GetRescaleIntercept()
01637 {
01638    // 0028 1052 DS IMG Rescale Intercept
01639    DataEntry *entry = GetDataEntry(0x0028, 0x1052);
01640    if( !entry )
01641    {
01642       gdcmWarningMacro( "Missing Rescale Intercept (0028,1052)");
01643       return 0.0f;
01644    }
01645    return (float)entry->GetValue(0);
01646 
01647 }
01648 
01653 double File::GetRescaleSlope()
01654 {
01655    double resInter = 0.;
01656    double resSlope = 1.;
01657    if ( GetRescaleSlopeIntercept(resSlope, resInter) )
01658      {
01659      return resSlope;
01660      }
01661    //0028 1053 DS IMG Rescale Slope
01662    std::string strRescSlope = GetEntryString(0x0028,0x1053);
01663    if ( strRescSlope != GDCM_UNFOUND )
01664    {
01665       if ( sscanf( strRescSlope.c_str(), "%lf ", &resSlope) != 1 )
01666       {
01667          // bug in the element 0x0028,0x1053
01668          gdcmWarningMacro( "Rescale Slope (0028,1053) is empty.");
01669       }
01670    }
01671 
01672    return resSlope;
01673 }
01674 
01682 int File::GetNumberOfScalarComponents()
01683 {
01684    if ( GetSamplesPerPixel() == 3 )
01685    {
01686       return 3;
01687    }
01688 
01689    // 0028 0100 US IMG Bits Allocated
01690    // (in order no to be messed up by old RGB images)
01691    if ( GetEntryString(0x0028,0x0100) == "24" )
01692    {
01693       return 3;
01694    }
01695 
01696    std::string strPhotometricInterpretation = GetEntryString(0x0028,0x0004);
01697 
01698    if ( ( strPhotometricInterpretation == "PALETTE COLOR ") )
01699    {
01700       if ( HasLUT() )// PALETTE COLOR is NOT enough
01701       {
01702          return 3;
01703       }
01704       else
01705       {
01706          return 1;
01707       }
01708    }
01709 
01710    // beware of trailing space at end of string      
01711    // DICOM tags are never of odd length
01712    if ( strPhotometricInterpretation == GDCM_UNFOUND   || 
01713         Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME1") ||
01714         Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME2") )
01715    {
01716       return 1;
01717    }
01718    else
01719    {
01720       // we assume that *all* kinds of YBR are dealt with
01721       return 3;
01722    }
01723 }
01724 
01732 int File::GetNumberOfScalarComponentsRaw()
01733 {
01734    // 0028 0100 US IMG Bits Allocated
01735    // (in order no to be messed up by old RGB images)
01736    if ( File::GetEntryString(0x0028,0x0100) == "24" )
01737    {
01738       return 3;
01739    }
01740 
01741    // we assume that *all* kinds of YBR are dealt with
01742    return GetSamplesPerPixel();
01743 }
01744 
01750 size_t File::GetPixelOffset()
01751 {
01752    DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel);
01753    if ( pxlElement )
01754    {
01755       return pxlElement->GetOffset();
01756    }
01757    else
01758    {
01759       gdcmWarningMacro( "Big trouble : Pixel Element ("
01760                       << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" );
01761       return 0;
01762    }
01763 }
01764 
01772 size_t File::GetPixelAreaLength()
01773 {
01774    DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel);
01775    if ( pxlElement )
01776    {
01777       return pxlElement->GetLength();
01778    }
01779    else
01780    {
01781       gdcmWarningMacro( "Big trouble : Pixel Element ("
01782                       << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" );
01783       return 0;
01784    }
01785 }
01786 
01793 void File::AddAnonymizeElement (uint16_t group, uint16_t elem, 
01794                                 std::string const &value) 
01795 { 
01796    DicomElement el;
01797    el.Group = group;
01798    el.Elem  = elem;
01799    el.Value = value;
01800    UserAnonymizeList.push_back(el); 
01801 }
01802 
01807 void File::AnonymizeNoLoad()
01808 {
01809    std::fstream *fp = new std::fstream(Filename.c_str(), 
01810                               std::ios::in | std::ios::out | std::ios::binary); 
01811    GDCM_NAME_SPACE::DocEntry *d;
01812    uint32_t offset;
01813    uint32_t lgth;
01814    uint32_t valLgth = 0;
01815    std::string *spaces;
01816    for (ListElements::iterator it = UserAnonymizeList.begin();  
01817                                it != UserAnonymizeList.end();
01818                              ++it)
01819    { 
01820    
01821       //std::cout << "File::AnonymizeNoLoad -------" << std::hex <<(*it).Group <<"|"<< 
01822       //         (*it).Elem 
01823       //         << "[" << (*it).Value << "] "<< std::dec << std::endl; 
01824       d = GetDocEntry( (*it).Group, (*it).Elem);
01825 
01826       if ( d == NULL)
01827          continue;
01828 
01829       if ( dynamic_cast<SeqEntry *>(d) )
01830       {
01831          gdcmWarningMacro( "You cannot 'Anonymize' a SeqEntry ");
01832          continue;
01833       }
01834 
01835       valLgth = (*it).Value.size();
01836       if (valLgth == 0)
01837          continue;
01838 
01839       offset = d->GetOffset();
01840       lgth =   d->GetLength();
01841       
01842       //std::cout << "lgth " << lgth << " valLgth " << valLgth << std::endl;
01843       if (valLgth < lgth)
01844       {
01845          spaces = new std::string( lgth-valLgth, ' ');
01846          (*it).Value = (*it).Value + *spaces;
01847          //std::cout << "[" << (*it).Value << "] " << lgth << std::endl;
01848          delete spaces;
01849       }
01850       fp->seekp( offset, std::ios::beg );
01851       fp->write( (*it).Value.c_str(), lgth );
01852      
01853    }
01854    fp->close();
01855    delete fp;
01856 }
01857 
01863 bool File::AnonymizeFile()
01864 {
01865    // If Anonymisation list is empty, let's perform some basic anonymization
01866    if ( UserAnonymizeList.begin() == UserAnonymizeList.end() )
01867    {
01868       // If exist, replace by spaces
01869       SetEntryString("  ",0x0010, 0x2154); // Telephone   
01870       SetEntryString("  ",0x0010, 0x1040); // Adress
01871       SetEntryString("  ",0x0010, 0x0020); // Patient ID
01872 
01873       DocEntry *patientNameHE = GetDocEntry (0x0010, 0x0010);
01874   
01875       if ( patientNameHE ) // we replace it by Study Instance UID (why not ?)
01876       {
01877          std::string studyInstanceUID =  GetEntryString (0x0020, 0x000d);
01878          if ( studyInstanceUID != GDCM_UNFOUND )
01879          {
01880             SetEntryString(studyInstanceUID, 0x0010, 0x0010);
01881          }
01882          else
01883          {
01884             SetEntryString("anonymized", 0x0010, 0x0010);
01885          }
01886       }
01887    }
01888    else
01889    {
01890       GDCM_NAME_SPACE::DocEntry *d;
01891       for (ListElements::iterator it = UserAnonymizeList.begin();  
01892                                   it != UserAnonymizeList.end();
01893                                 ++it)
01894       {  
01895          d = GetDocEntry( (*it).Group, (*it).Elem);
01896 
01897          if ( d == NULL)
01898             continue;
01899 
01900          if ( dynamic_cast<SeqEntry *>(d) )
01901          {
01902             gdcmWarningMacro( "You cannot 'Anonymize' a SeqEntry ");
01903             continue;
01904          }
01905 
01906          if ( dynamic_cast<DataEntry *>(d) )
01907          {
01908             gdcmWarningMacro( "To 'Anonymize' a DataEntry, better use AnonymizeNoLoad (FIXME) ");
01909             continue;
01910          }
01911          else
01912             SetEntryString ((*it).Value, (*it).Group, (*it).Elem);
01913       }
01914 }
01915 
01916   // In order to make definitively impossible any further identification
01917   // remove or replace all the stuff that contains a Date
01918 
01919 //0008 0012 DA ID Instance Creation Date
01920 //0008 0020 DA ID Study Date
01921 //0008 0021 DA ID Series Date
01922 //0008 0022 DA ID Acquisition Date
01923 //0008 0023 DA ID Content Date
01924 //0008 0024 DA ID Overlay Date
01925 //0008 0025 DA ID Curve Date
01926 //0008 002a DT ID Acquisition Datetime
01927 //0018 9074 DT ACQ Frame Acquisition Datetime
01928 //0018 9151 DT ACQ Frame Reference Datetime
01929 //0018 a002 DT ACQ Contribution Date Time
01930 //0020 3403 SH REL Modified Image Date (RET)
01931 //0032 0032 DA SDY Study Verified Date
01932 //0032 0034 DA SDY Study Read Date
01933 //0032 1000 DA SDY Scheduled Study Start Date
01934 //0032 1010 DA SDY Scheduled Study Stop Date
01935 //0032 1040 DA SDY Study Arrival Date
01936 //0032 1050 DA SDY Study Completion Date
01937 //0038 001a DA VIS Scheduled Admission Date
01938 //0038 001c DA VIS Scheduled Discharge Date
01939 //0038 0020 DA VIS Admitting Date
01940 //0038 0030 DA VIS Discharge Date
01941 //0040 0002 DA PRC Scheduled Procedure Step Start Date
01942 //0040 0004 DA PRC Scheduled Procedure Step End Date
01943 //0040 0244 DA PRC Performed Procedure Step Start Date
01944 //0040 0250 DA PRC Performed Procedure Step End Date
01945 //0040 2004 DA PRC Issue Date of Imaging Service Request
01946 //0040 4005 DT PRC Scheduled Procedure Step Start Date and Time
01947 //0040 4011 DT PRC Expected Completion Date and Time
01948 //0040 a030 DT PRC Verification Date Time
01949 //0040 a032 DT PRC Observation Date Time
01950 //0040 a120 DT PRC DateTime
01951 //0040 a121 DA PRC Date
01952 //0040 a13a DT PRC Referenced Datetime
01953 //0070 0082 DA ??? Presentation Creation Date
01954 //0100 0420 DT ??? SOP Autorization Date and Time
01955 //0400 0105 DT ??? Digital Signature DateTime
01956 //2100 0040 DA PJ Creation Date
01957 //3006 0008 DA SSET Structure Set Date
01958 //3008 0024 DA ??? Treatment Control Point Date
01959 //3008 0054 DA ??? First Treatment Date
01960 //3008 0056 DA ??? Most Recent Treatment Date
01961 //3008 0162 DA ??? Safe Position Exit Date
01962 //3008 0166 DA ??? Safe Position Return Date
01963 //3008 0250 DA ??? Treatment Date
01964 //300a 0006 DA RT RT Plan Date
01965 //300a 022c DA RT Air Kerma Rate Reference Date
01966 //300e 0004 DA RT Review Date
01967 
01968    return true;
01969 }
01970 
01979 bool File::Write(std::string fileName, FileType writetype)
01980 {
01981       gdcmDebugMacro(" File::Write ");
01982    std::ofstream *fp = new std::ofstream(fileName.c_str(), 
01983                                          std::ios::out | std::ios::binary);
01984    if (*fp == NULL)
01985    {
01986       gdcmWarningMacro("Failed to open (write) File: " << fileName.c_str());
01987       return false;
01988    }
01989 
01990    // Entry : 0002|0000 = group length -> recalculated
01991    DataEntry *e0000 = GetDataEntry(0x0002,0x0000);
01992    if ( e0000 )
01993    {
01994       std::ostringstream sLen;
01995       sLen << ComputeGroup0002Length( );
01996       e0000->SetString(sLen.str());
01997    }
01998 
02000    if( writetype != JPEG )
02001    {
02002       int i_lgPix = GetEntryLength(GrPixel, NumPixel);
02003       if (i_lgPix != -2)
02004       {
02005          // no (GrPixel, NumPixel) element
02006          std::string s_lgPix = Util::Format("%d", i_lgPix+12);
02007          s_lgPix = Util::DicomString( s_lgPix.c_str() );
02008          InsertEntryString(s_lgPix,GrPixel, 0x0000, "UL");
02009       }
02010    }
02011    Document::WriteContent(fp, writetype);
02012 
02013    fp->close();
02014    delete fp;
02015 
02016    return true;
02017 }
02018 
02019 //-----------------------------------------------------------------------------
02020 // Protected
02021 
02022 
02023 //-----------------------------------------------------------------------------
02024 // Private
02030 void File::ComputeRLEInfo()
02031 {
02032    std::string ts = GetTransferSyntax();
02033    if ( !Global::GetTS()->IsRLELossless(ts) ) 
02034    {
02035       return;
02036    }
02037 
02038    // Encoded pixel data: for the time being we are only concerned with
02039    // Jpeg or RLE Pixel data encodings.
02040    // As stated in PS 3.5-2003, section 8.2 p44:
02041    // "If sent in Encapsulated Format (i.e. other than the Native Format) the
02042    //  value representation OB is used".
02043    // Hence we expect an OB value representation. Concerning OB VR,
02044    // the section PS 3.5-2003, section A.4.c p 58-59, states:
02045    // "For the Value Representations OB and OW, the encoding shall meet the
02046    //   following specifications depending on the Data element tag:"
02047    //   [...snip...]
02048    //    - the first item in the sequence of items before the encoded pixel
02049    //      data stream shall be basic offset table item. The basic offset table
02050    //      item value, however, is not required to be present"
02051    ReadEncapsulatedBasicOffsetTable();
02052 
02053    // Encapsulated RLE Compressed Images (see PS 3.5-2003, Annex G)
02054    // Loop on the individual frame[s] and store the information
02055    // on the RLE fragments in a RLEFramesInfo.
02056    // Note: - when only a single frame is present, this is a
02057    //         classical image.
02058    //       - when more than one frame are present, then we are in 
02059    //         the case of a multi-frame image.
02060    long frameLength;
02061    int i=0;
02062    uint32_t sum = 0;
02063    while ( (frameLength = ReadTagLength(0xfffe, 0xe000)) != 0 )
02064    { 
02065       // Since we have read the basic offset table, let's check the value were correct
02066       // or else produce a warning:
02067       if ( BasicOffsetTableItemValue )
02068         {
02069         // If a BasicOffsetTableItemValue was read
02070         uint32_t individualLength = BasicOffsetTableItemValue[i];
02071         assert( individualLength == sum ); // REMOVE that if this is a problem
02072         if( individualLength != sum )
02073           {
02074           gdcmWarningMacro( "BasicOffsetTableItemValue differs from the fragment lenght" );
02075           }
02076         sum += frameLength + 8;
02077         i++;
02078         }
02079       // Parse the RLE Header and store the corresponding RLE Segment
02080       // Offset Table information on fragments of this current Frame.
02081       // Note that the fragment pixels themselves are not loaded
02082       // (but just skipped).
02083       long frameOffset = Fp->tellg(); // once per fragment
02084 
02085       uint32_t nbRleSegments = ReadInt32();
02086       if ( nbRleSegments > 16 )
02087       {
02088          // There should be at most 15 segments (refer to RLEFrame class)
02089          gdcmWarningMacro( "Too many segments.");
02090       }
02091  
02092       uint32_t rleSegmentOffsetTable[16];
02093       for( int k = 1; k <= 15; k++ )
02094       {
02095          rleSegmentOffsetTable[k] = ReadInt32();
02096       }
02097 
02098       // Deduce from both RLE Header and frameLength 
02099       // the fragment length, and again store this info
02100       // in a RLEFramesInfo.
02101       long rleSegmentLength[15];
02102       // skipping (not reading) RLE Segments
02103       if ( nbRleSegments > 1)
02104       {
02105          for(unsigned int k = 1; k <= nbRleSegments-1; k++)
02106          {
02107              rleSegmentLength[k] =  rleSegmentOffsetTable[k+1]
02108                                   - rleSegmentOffsetTable[k];
02109              SkipBytes(rleSegmentLength[k]);
02110           }
02111        }
02112 
02113        rleSegmentLength[nbRleSegments] = frameLength 
02114                                       - rleSegmentOffsetTable[nbRleSegments];
02115        SkipBytes(rleSegmentLength[nbRleSegments]);
02116 
02117        // Store the collected info
02118        RLEFrame *newFrame = new RLEFrame;
02119        newFrame->SetNumberOfFragments(nbRleSegments);
02120        for( unsigned int uk = 1; uk <= nbRleSegments; uk++ )
02121        {
02122           newFrame->SetOffset(uk,frameOffset + rleSegmentOffsetTable[uk]);
02123           newFrame->SetLength(uk,rleSegmentLength[uk]);
02124        }
02125        RLEInfo->AddFrame(newFrame);
02126    }
02127 
02128    // Make sure that  we encounter a 'Sequence Delimiter Item'
02129    // at the end of the item :
02130    if ( !ReadTag(0xfffe, 0xe0dd) ) // once per RLE File
02131    {
02132       gdcmWarningMacro( "No sequence delimiter item at end of RLE item sequence");
02133    }
02134 }
02135 
02142 void File::ComputeJPEGFragmentInfo()
02143 {
02144    // If you need to, look for comments of ComputeRLEInfo().
02145    std::string ts = GetTransferSyntax();
02146    if ( ! Global::GetTS()->IsJPEG(ts) )
02147    {
02148       return;
02149    }
02150 
02151    ReadEncapsulatedBasicOffsetTable();
02152 
02153    // Loop on the fragments[s] and store the parsed information in a
02154    // JPEGInfo.
02155    long fragmentLength;
02156    int i=0;
02157    uint32_t sum = 0;
02158    while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) != 0 )
02159    { 
02160       // Since we have read the basic offset table, let's check the value were correct
02161       // or else produce a warning:
02162       // A.4 Transfer syntaxes for encapsulation of encoded pixel data:
02163       // When the Item Value is present, the Basic Offset Table Item Value shall contain
02164       // concatenated 32-bit unsigned integer values that are byte offsets to the first
02165       // byte of the Item Tag of the first fragment for each frame in the Sequence of
02166       // Items. These offsets are measured from the first byte of the first Item Tag
02167       // following the Basic Offset Table item (See Table A.4-2).
02168 
02169       if ( BasicOffsetTableItemValue )
02170         {
02171         // If a BasicOffsetTableItemValue was read
02172         uint32_t individualLength = BasicOffsetTableItemValue[i];
02173         //assert( individualLength == sum ); // Seems like 00191113.dcm is off by one ??
02174         if( individualLength != sum )
02175           {
02176           gdcmWarningMacro( "BasicOffsetTableItemValue differs from the fragment lenght:" <<
02177               individualLength << " != " << sum );
02178           }
02179         sum += fragmentLength + 8;
02180         i++;
02181         }
02182 
02183       long fragmentOffset = Fp->tellg(); // Once per fragment
02184       // Store the collected info
02185       JPEGFragment *newFragment = new JPEGFragment;
02186       newFragment->SetOffset(fragmentOffset);
02187       newFragment->SetLength(fragmentLength);
02188       JPEGInfo->AddFragment(newFragment);
02189 
02190       SkipBytes(fragmentLength);
02191    }
02192 
02193    // Make sure that  we encounter a 'Sequence Delimiter Item'
02194    // at the end of the item :
02195    if ( !ReadTag(0xfffe, 0xe0dd) )
02196    {
02197       gdcmWarningMacro( "No sequence delimiter item at end of JPEG item sequence");
02198    }
02199 }
02200 
02214 bool File::ReadTag(uint16_t testGroup, uint16_t testElem)
02215 {
02216    long positionOnEntry = Fp->tellg(); // Only when reading fragments
02217    //long currentPosition = positionOnEntry;      // On debugging purposes
02218 
02219    // Read the Item Tag group and element, and make
02220    // sure they are what we expected:
02221    uint16_t itemTagGroup;
02222    uint16_t itemTagElem;
02223    try
02224    {
02225       itemTagGroup = ReadInt16();
02226       itemTagElem  = ReadInt16();
02227    }
02228    catch ( FormatError )
02229    {
02230       gdcmErrorMacro( "Can not read tag for "
02231        << "   We should have found tag ("
02232        << DictEntry::TranslateToKey(testGroup,testElem) << ")"
02233        ) ;
02234 
02235       return false;
02236    }
02237    if ( itemTagGroup != testGroup || itemTagElem != testElem )
02238    {
02239        // in order not to pollute output we don't warn on 'delimitors'
02240       if (itemTagGroup != 0xfffe ||  testGroup != 0xfffe )
02241          gdcmWarningMacro( "Wrong Item Tag found:"
02242           << "   We should have found tag ("
02243           << DictEntry::TranslateToKey(testGroup,testElem) << ")" << std::endl
02244           << "   but instead we encountered tag ("
02245           << DictEntry::TranslateToKey(itemTagGroup,itemTagElem) << ")"
02246           << "  at address: " << "  0x(" << std::hex 
02247           << (unsigned int)positionOnEntry  << std::dec << ")"
02248           ) ;
02249       Fp->seekg(positionOnEntry, std::ios::beg);
02250 
02251       return false;
02252    }
02253    return true;
02254 }
02255 
02270 uint32_t File::ReadTagLength(uint16_t testGroup, uint16_t testElem)
02271 {
02272 
02273    if ( !ReadTag(testGroup, testElem) )
02274    {
02275       // Avoid polutting output
02276       if ( testGroup != 0xfffe ) 
02277          gdcmErrorMacro( "ReadTag did not succeed for ("
02278                     << DictEntry::TranslateToKey(testGroup,testElem) 
02279                     << ")..." );
02280       return 0;
02281    }
02282                                                                                 
02284 
02285    // long currentPosition = Fp->tellg(); // save time // JPRx
02286    uint32_t itemLength  = ReadInt32();
02287    gdcmDebugMacro( "Basic Item Length is: " << itemLength 
02288 //        << "  at address: " << std::hex << (unsigned int)currentPosition
02289    );
02290    return itemLength;
02291 }
02292 
02297 void File::ReadEncapsulatedBasicOffsetTable()
02298 {
02300    uint32_t itemLength = ReadTagLength(0xfffe, 0xe000);
02301 
02302    // When present, read the basic offset table itself.
02303    // Notes: - since the presence of this basic offset table is optional
02304    //          we can't rely on it for the implementation, and we will simply
02305    //          trash its content (when present).
02306    //        - still, when present, we could add some further checks on the
02307    //          lengths, but we won't bother with such fuses for the time being.
02308    if ( itemLength != 0 )
02309    {
02310       char *charBasicOffsetTableItemValue = new char[itemLength];
02311       Fp->read(charBasicOffsetTableItemValue, itemLength);
02312       unsigned int nbEntries = itemLength/4;
02313       assert( nbEntries*4 == itemLength); // Make sure this is a multiple
02314       BasicOffsetTableItemValue = new uint32_t[nbEntries];
02315 
02316       for (unsigned int i=0; i < nbEntries; i++ )
02317       {
02318          BasicOffsetTableItemValue[i] = *((uint32_t*)(&charBasicOffsetTableItemValue[4*i]));
02319 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
02320          uint32_t val = BasicOffsetTableItemValue[i];
02321          BasicOffsetTableItemValue[i] 
02322            = (  (val<<24)               | ((val<<8)  & 0x00ff0000) | 
02323               ( (val>>8)  & 0x0000ff00) |  (val>>24)               );
02324 #endif
02325          gdcmDebugMacro( "Read one length for: " << 
02326                           std::hex << BasicOffsetTableItemValue[i] );
02327       }
02328 
02329       delete[] charBasicOffsetTableItemValue;
02330    }
02331 }
02332 
02333 // These are the deprecated method that one day should be removed (after the next release)
02334 
02335 //#ifndef GDCM_LEGACY_REMOVE
02336 /*
02337  * \ brief   Loader. (DEPRECATED :  temporaryly kept not to break the API)
02338  * @ param   fileName file to be open for parsing
02339  * @ return false if file cannot be open or no swap info was found,
02340  *         or no tag was found.
02341  * @deprecated Use the Load() [ + SetLoadMode() ] + SetFileName() functions instead
02342  */
02343  /*
02344 bool File::Load( std::string const &fileName ) 
02345 {
02346    GDCM_LEGACY_REPLACED_BODY(File::Load(std::string), "1.2",
02347                              File::Load());
02348    SetFileName( fileName );
02349    if ( ! this->Document::Load( ) )
02350       return false;
02351 
02352    return DoTheLoadingJob( );
02353 }
02354 #endif
02355 */
02356 //-----------------------------------------------------------------------------
02357 // Print
02358 
02359 //-----------------------------------------------------------------------------
02360 } // end namespace gdcm

Generated on Fri Aug 24 12:59:31 2007 for gdcm by  doxygen 1.4.6