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

vtkGdcmReader.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002                                                                                 
00003   Program:   gdcm
00004   Module:    $RCSfile: vtkGdcmReader.cxx,v $
00005   Language:  C++
00006   Date:      $Date: 2005/01/21 11:40:56 $
00007   Version:   $Revision: 1.66 $
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 // //////////////////////////////////////////////////////////////
00021 // WARNING TODO CLEANME 
00022 // Actual limitations of this code:
00023 //
00024 // /////// Redundant and unnecessary header parsing
00025 // In it's current state this code actually parses three times the Dicom
00026 // header of a file before the corresponding image gets loaded in the
00027 // ad-hoc vtkData !
00028 // Here is the process:
00029 //  1/ First loading happens in ExecuteInformation which in order to
00030 //     positionate the vtk extents calls CheckFileCoherence. The purpose
00031 //     of CheckFileCoherence is to make sure all the images in the future
00032 //     stack are "homogenous" (same size, same representation...). This
00033 //     can only be achieved by parsing all the Dicom headers...
00034 //  2/ ExecuteData is then responsible for the next two loadings:
00035 //  2a/ ExecuteData calls AllocateOutputData that in turn seems to 
00036 //      (indirectely call) ExecuteInformation which ends up in a second
00037 //      header parsing
00038 //      This is fixed by adding a test at the beginning of ExecuteInformation
00039 //      on the modification of the object instance. If a modification have been
00040 //      made (method Modified() ), the MTime value is increased. The fileTime
00041 //      is compared to this new value to find a modification in the class
00042 //      parameters
00043 //  2b/ the core of ExecuteData then needs gdcmFile (which in turns
00044 //      initialises gdcmFile in the constructor) in order to access
00045 //      the data-image.
00046 //
00047 // Possible solution:
00048 // maintain a list of gdcmFiles (created by say ExecuteInformation) created
00049 // once and for all accross the life of vtkGdcmFile (it would only load
00050 // new gdcmFile if the user changes the list). ExecuteData would then use 
00051 // those gdcmFile and hence avoid calling the construtor:
00052 //  - advantage: the header of the files would only be parser once.
00053 //  - drawback: once execute information is called (i.e. on creation of
00054 //              a vtkGdcmFile) the gdcmFile structure is loaded in memory.
00055 //              The average size of a gdcmFile being of 100Ko, is one
00056 //              loads 10 stacks of images with say 200 images each, you
00057 //              end-up with a loss of 200Mo...
00058 //
00059 // /////// Never unallocated memory:
00060 // ExecuteData allocates space for the pixel data [which will get pointed
00061 // by the vtkPointData() through the call
00062 // data->GetPointData()->GetScalars()->SetVoidArray(mem, StackNumPixels, 0);]
00063 // This data is never "freed" neither in the destructor nor when the
00064 // filename list is extended, ExecuteData is called a second (or third)
00065 // time...
00066 // //////////////////////////////////////////////////////////////
00067 
00068 #include "gdcmFileHelper.h"
00069 #include "gdcmFile.h"
00070 #include "vtkGdcmReader.h"
00071 
00072 //#include <stdio.h>
00073 #include <vtkObjectFactory.h>
00074 #include <vtkImageData.h>
00075 #include <vtkPointData.h>
00076 #include <vtkLookupTable.h>
00077 
00078 vtkCxxRevisionMacro(vtkGdcmReader, "$Revision: 1.66 $");
00079 vtkStandardNewMacro(vtkGdcmReader);
00080 
00081 //-----------------------------------------------------------------------------
00082 // Constructor / Destructor
00083 vtkGdcmReader::vtkGdcmReader()
00084 {
00085    this->LookupTable = NULL;
00086    this->AllowLookupTable = 0;
00087 }
00088 
00089 vtkGdcmReader::~vtkGdcmReader()
00090 {
00091    this->RemoveAllFileName();
00092    this->InternalFileNameList.clear();
00093    if(this->LookupTable) 
00094       this->LookupTable->Delete();
00095 }
00096 
00097 //-----------------------------------------------------------------------------
00098 // Print
00099 void vtkGdcmReader::PrintSelf(ostream& os, vtkIndent indent)
00100 {
00101    this->Superclass::PrintSelf(os,indent);
00102    os << indent << "Filenames  : " << endl;
00103    vtkIndent nextIndent = indent.GetNextIndent();
00104    for (std::list<std::string>::iterator it = FileNameList.begin();
00105         it != FileNameList.end();
00106         ++it)
00107    {
00108       os << nextIndent << it->c_str() << endl ;
00109    }
00110 }
00111 
00112 //-----------------------------------------------------------------------------
00113 // Public
00114 /*
00115  * Remove all files from the list of images to read.
00116  */
00117 void vtkGdcmReader::RemoveAllFileName(void)
00118 {
00119    this->FileNameList.clear();
00120    this->Modified();
00121 }
00122 
00123 /*
00124  * Adds a file name to the list of images to read.
00125  */
00126 void vtkGdcmReader::AddFileName(const char* name)
00127 {
00128    // We need to bypass the const pointer [since list<>.push_bash() only
00129    // takes a char* (but not a const char*)] by making a local copy:
00130    char * LocalName = new char[strlen(name) + 1];
00131    strcpy(LocalName, name);
00132    this->FileNameList.push_back(LocalName);
00133    delete[] LocalName;
00134    this->Modified();
00135 }
00136 
00137 /*
00138  * Sets up a filename to be read.
00139  */
00140 void vtkGdcmReader::SetFileName(const char *name) 
00141 {
00142    vtkImageReader2::SetFileName(name);
00143    // Since we maintain a list of filenames, when building a volume,
00144    // (see vtkGdcmReader::AddFileName), we additionaly need to purge
00145    // this list when we manually positionate the filename.
00146    vtkDebugMacro(<< "Clearing all files given with AddFileName");
00147    this->FileNameList.clear();
00148    this->Modified();
00149 }
00150 
00151 //-----------------------------------------------------------------------------
00152 // Protected
00153 /*
00154  * Configure the output e.g. WholeExtent, spacing, origin, scalar type...
00155  */
00156 void vtkGdcmReader::ExecuteInformation()
00157 {
00158    if(this->MTime>this->fileTime)
00159    {
00160       this->TotalNumberOfPlanes = this->CheckFileCoherence();
00161       if ( this->TotalNumberOfPlanes == 0)
00162       {
00163          vtkErrorMacro(<< "File set is not coherent. Exiting...");
00164          return;
00165       }
00166       
00167       // if the user has not set the extent, but has set the VOI
00168       // set the z axis extent to the VOI z axis
00169       if (this->DataExtent[4]==0 && this->DataExtent[5] == 0 &&
00170       (this->DataVOI[4] || this->DataVOI[5]))
00171       {
00172          this->DataExtent[4] = this->DataVOI[4];
00173          this->DataExtent[5] = this->DataVOI[5];
00174       }
00175 
00176       // When the user has set the VOI, check it's coherence with the file content.
00177       if (this->DataVOI[0] || this->DataVOI[1] || 
00178       this->DataVOI[2] || this->DataVOI[3] ||
00179       this->DataVOI[4] || this->DataVOI[5])
00180       { 
00181          if ((this->DataVOI[0] < 0) ||
00182              (this->DataVOI[1] >= this->NumColumns) ||
00183              (this->DataVOI[2] < 0) ||
00184              (this->DataVOI[3] >= this->NumLines) ||
00185              (this->DataVOI[4] < 0) ||
00186              (this->DataVOI[5] >= this->TotalNumberOfPlanes ))
00187          {
00188             vtkWarningMacro(<< "The requested VOI is larger than expected extent.");
00189             this->DataVOI[0] = 0;
00190             this->DataVOI[1] = this->NumColumns - 1;
00191             this->DataVOI[2] = 0;
00192             this->DataVOI[3] = this->NumLines - 1;
00193             this->DataVOI[4] = 0;
00194             this->DataVOI[5] = this->TotalNumberOfPlanes - 1;
00195          }
00196       }
00197 
00198       // Positionate the Extent.
00199       this->DataExtent[0] = 0;
00200       this->DataExtent[1] = this->NumColumns - 1;
00201       this->DataExtent[2] = 0;
00202       this->DataExtent[3] = this->NumLines - 1;
00203       this->DataExtent[4] = 0;
00204       this->DataExtent[5] = this->TotalNumberOfPlanes - 1;
00205   
00206       // We don't need to positionate the Endian related stuff (by using
00207       // this->SetDataByteOrderToBigEndian() or SetDataByteOrderToLittleEndian()
00208       // since the reading of the file is done by gdcm.
00209       // But we do need to set up the data type for downstream filters:
00210       if      ( ImageType == "8U" )
00211       {
00212          vtkDebugMacro(<< "8 bits unsigned image");
00213          this->SetDataScalarTypeToUnsignedChar(); 
00214       }
00215       else if ( ImageType == "8S" )
00216       {
00217          vtkErrorMacro(<< "Cannot handle 8 bit signed files");
00218          return;
00219       }
00220       else if ( ImageType == "16U" )
00221       {
00222          vtkDebugMacro(<< "16 bits unsigned image");
00223          this->SetDataScalarTypeToUnsignedShort();
00224       }
00225       else if ( ImageType == "16S" )
00226       {
00227          vtkDebugMacro(<< "16 bits signed image");
00228          this->SetDataScalarTypeToShort();
00229          //vtkErrorMacro(<< "Cannot handle 16 bit signed files");
00230       }
00231       else if ( ImageType == "32U" )
00232       {
00233          vtkDebugMacro(<< "32 bits unsigned image");
00234          vtkDebugMacro(<< "WARNING: forced to signed int !");
00235          this->SetDataScalarTypeToInt();
00236       }
00237       else if ( ImageType == "32S" )
00238       {
00239          vtkDebugMacro(<< "32 bits signed image");
00240          this->SetDataScalarTypeToInt();
00241       }
00242       else if ( ImageType == "FD" )
00243       {
00244          vtkDebugMacro(<< "64 bits Double image");
00245          this->SetDataScalarTypeToDouble();
00246       }
00247       //Set number of scalar components:
00248       this->SetNumberOfScalarComponents(this->NumComponents);
00249 
00250       this->fileTime=this->MTime;
00251    }
00252 
00253    this->Superclass::ExecuteInformation();
00254 }
00255 
00256 /*
00257  * Update => ouput->Update => UpdateData => Execute => ExecuteData 
00258  * (see vtkSource.cxx for last step).
00259  * This function (redefinition of vtkImageReader::ExecuteData, see 
00260  * VTK/IO/vtkImageReader.cxx) reads a data from a file. The datas
00261  * extent/axes are assumed to be the same as the file extent/order.
00262  */
00263 void vtkGdcmReader::ExecuteData(vtkDataObject *output)
00264 {
00265    if (this->InternalFileNameList.empty())
00266    {
00267       vtkErrorMacro(<< "A least a valid FileName must be specified.");
00268       return;
00269    }
00270 
00271    // FIXME : extraneous parsing of header is made when allocating OuputData
00272    vtkImageData *data = this->AllocateOutputData(output);
00273    data->SetExtent(this->DataExtent);
00274    data->GetPointData()->GetScalars()->SetName("DicomImage-Volume");
00275 
00276    // Test if output has valid extent
00277    // Prevent memory errors
00278    if((this->DataExtent[1]-this->DataExtent[0]>=0) &&
00279       (this->DataExtent[3]-this->DataExtent[2]>=0) &&
00280       (this->DataExtent[5]-this->DataExtent[4]>=0))
00281    {
00282       // The memory size for a full stack of images of course depends
00283       // on the number of planes and the size of each image:
00284       //size_t StackNumPixels = this->NumColumns * this->NumLines
00285       //                      * this->TotalNumberOfPlanes * this->NumComponents;
00286       //size_t stack_size = StackNumPixels * this->PixelSize; //not used
00287       // Allocate pixel data space itself.
00288 
00289       // Variables for the UpdateProgress. We shall use 50 steps to signify
00290       // the advance of the process:
00291       unsigned long UpdateProgressTarget = (unsigned long) ceil (this->NumLines
00292                                          * this->TotalNumberOfPlanes
00293                                          / 50.0);
00294       // The actual advance measure:
00295       unsigned long UpdateProgressCount = 0;
00296 
00297       // Feeling the allocated memory space with each image/volume:
00298       unsigned char *Dest = (unsigned char *)data->GetScalarPointer();
00299       for (std::list<std::string>::iterator filename  = InternalFileNameList.begin();
00300            filename != InternalFileNameList.end();
00301            ++filename)
00302       { 
00303          // Images that were tagged as unreadable in CheckFileCoherence()
00304          // are substituted with a black image to let the caller visually
00305          // notice something wrong is going on:
00306          if (*filename != "GDCM_UNREADABLE")
00307          {
00308             // Update progress related for good files is made in LoadImageInMemory
00309             Dest += this->LoadImageInMemory(*filename, Dest,
00310                                             UpdateProgressTarget,
00311                                             UpdateProgressCount);
00312          } 
00313          else 
00314          {
00315             // We insert a black image in the stack for the user to be aware that
00316             // this image/volume couldn't be loaded. We simply skip one image
00317             // size:
00318             Dest += this->NumColumns * this->NumLines * this->PixelSize;
00319 
00320             // Update progress related for bad files:
00321             UpdateProgressCount += this->NumLines;
00322             if (UpdateProgressTarget > 0)
00323             {
00324                if (!(UpdateProgressCount%UpdateProgressTarget))
00325                {
00326                   this->UpdateProgress(UpdateProgressCount/(50.0*UpdateProgressTarget));
00327                }
00328             }
00329          } // Else, file not loadable
00330       } // Loop on files
00331    }
00332 }
00333 
00334 /*
00335  * vtkGdcmReader can have the file names specified through two ways:
00336  * (1) by calling the vtkImageReader2::SetFileName(), SetFilePrefix() and
00337  *     SetFilePattern()
00338  * (2) By successive calls to vtkGdcmReader::AddFileName()
00339  * When the first method was used by caller we need to update the local
00340  * filename list
00341  */
00342 void vtkGdcmReader::BuildFileListFromPattern()
00343 {
00344    this->RemoveAllInternalFileName();
00345 
00346    if ((! this->FileNameList.empty()) && this->FileName )
00347    {
00348       vtkErrorMacro(<< "Both AddFileName and SetFileName schemes were used");
00349       vtkErrorMacro(<< "No images loaded ! ");
00350       return;
00351    }
00352 
00353    if ((! this->FileNameList.empty()) && this->FilePrefix )
00354    {
00355       vtkErrorMacro(<< "Both AddFileName and SetFilePrefix schemes were used");
00356       vtkErrorMacro(<< "No images loaded ! ");
00357       return;
00358    }
00359 
00360    if (this->FileName && this->FilePrefix)
00361    {
00362       vtkErrorMacro(<< "Both SetFileName and SetFilePrefix schemes were used");
00363       vtkErrorMacro(<< "No images loaded ! ");
00364       return;
00365    }
00366 
00367    if (! this->FileNameList.empty()  )
00368    {
00369       vtkDebugMacro(<< "Using the AddFileName specified files");
00370       this->InternalFileNameList=this->FileNameList;
00371       return;
00372    }
00373 
00374    if (!this->FileName && !this->FilePrefix)
00375    {
00376       vtkErrorMacro(<< "FileNames are not set. Either use AddFileName() or");
00377       vtkErrorMacro(<< "specify a FileName or FilePrefix.");
00378       return;
00379    }
00380 
00381    if( this->FileName )
00382    {
00383       // Single file loading (as given with ::SetFileName()):
00384       // Case of multi-frame file considered here
00385       this->ComputeInternalFileName(this->DataExtent[4]);
00386       vtkDebugMacro(<< "Adding file " << this->InternalFileName);
00387       this->AddInternalFileName(this->InternalFileName);
00388    }
00389    else
00390    {
00391       // Multi file loading (as given with ::SetFilePattern()):
00392       for (int idx = this->DataExtent[4]; idx <= this->DataExtent[5]; ++idx)
00393       {
00394          this->ComputeInternalFileName(idx);
00395          vtkDebugMacro(<< "Adding file " << this->InternalFileName);
00396          this->AddInternalFileName(this->InternalFileName);
00397       }
00398    }
00399 }
00400 
00401 /*
00402  * When more than one filename is specified (i.e. we expect loading
00403  * a stack or volume) we need to check that the corresponding images/volumes
00404  * to be loaded are coherent i.e. to make sure:
00405  *     - they all share the same X dimensions
00406  *     - they all share the same Y dimensions
00407  *     - they all share the same ImageType ( 8 bit signed, or unsigned...)
00408  *
00409  * Eventually, we emit a warning when all the files do NOT share the
00410  * Z dimension, since we can still build a stack but the
00411  * files are not coherent in Z, which is probably a source a trouble...
00412  *   When files are not readable (either the file cannot be opened or
00413  * because gdcm cannot parse it), they are flagged as "GDCM_UNREADABLE".  
00414  *   This method returns the total number of planar images to be loaded
00415  * (i.e. an image represents one plane, but a volume represents many planes)
00416  */
00417 int vtkGdcmReader::CheckFileCoherence()
00418 {
00419    int ReturnedTotalNumberOfPlanes = 0;   // The returned value.
00420 
00421    this->BuildFileListFromPattern();
00422    if (this->InternalFileNameList.empty())
00423    {
00424       vtkErrorMacro(<< "FileNames are not set.");
00425       return 0;
00426    }
00427 
00428    bool FoundReferenceFile = false;
00429    int  ReferenceNZ = 0;
00430 
00431    // Loop on the filenames:
00432    // - check for their existence and gdcm "parsability"
00433    // - get the coherence check done:
00434    for (std::list<std::string>::iterator filename = InternalFileNameList.begin();
00435         filename != InternalFileNameList.end();
00436         ++filename)
00437    {
00438       // The file is always added in the number of planes
00439       //  - If file doesn't exist, it will be replaced by a black plane in the 
00440       //    ExecuteData method
00441       //  - If file has more than 1 plane, other planes will be added later to
00442       //    to the ReturnedTotalNumberOfPlanes variable counter
00443       ReturnedTotalNumberOfPlanes += 1;
00444 
00446       if(*filename == std::string("GDCM_UNREADABLE"))
00447          continue;
00448 
00450       // Stage 1.1: check for file existence.
00451       FILE *fp;
00452       fp = fopen(filename->c_str(),"rb");
00453       if (!fp)
00454       {
00455          vtkErrorMacro(<< "Unable to open file " << filename->c_str());
00456          vtkErrorMacro(<< "Removing this file from readed files "
00457                      << filename->c_str());
00458          *filename = "GDCM_UNREADABLE";
00459          continue;
00460       }
00461       fclose(fp);
00462 
00463       // Stage 1.2: check for Gdcm parsability
00464       gdcm::File GdcmFile(filename->c_str() );
00465       if (!GdcmFile.IsReadable())
00466       {
00467          vtkErrorMacro(<< "Gdcm cannot parse file " << filename->c_str());
00468          vtkErrorMacro(<< "Removing this file from readed files "
00469                         << filename->c_str());
00470          *filename = "GDCM_UNREADABLE";
00471          continue;
00472       }
00473 
00474       // Stage 1.3: further gdcm compatibility on PixelType
00475       std::string type = GdcmFile.GetPixelType();
00476       if (   (type !=  "8U") && (type !=  "8S")
00477           && (type != "16U") && (type != "16S")
00478           && (type != "32U") && (type != "32S") )
00479       {
00480          vtkErrorMacro(<< "Bad File Type for file " << filename->c_str() << "\n"
00481                        << "   File type found : " << type.c_str() 
00482                        << " (might be 8U, 8S, 16U, 16S, 32U, 32S) \n"
00483                        << "   Removing this file from readed files");
00484          *filename = "GDCM_UNREADABLE";
00485          continue;
00486       }
00487 
00488       // Stage 2: check coherence of the set of files
00489       int NX = GdcmFile.GetXSize();
00490       int NY = GdcmFile.GetYSize();
00491       int NZ = GdcmFile.GetZSize();
00492       if (FoundReferenceFile) 
00493       {
00494          // Stage 2.1: mandatory coherence stage:
00495          if (   ( NX   != this->NumColumns )
00496              || ( NY   != this->NumLines )
00497              || ( type != this->ImageType ) ) 
00498          {
00499             vtkErrorMacro(<< "This file is not coherent with previous ones"
00500                            << filename->c_str());
00501             vtkErrorMacro(<< "Removing this file from readed files "
00502                            << filename->c_str());
00503             *filename = "GDCM_UNREADABLE";
00504             continue;
00505          }
00506 
00507          // Stage 2.2: optional coherence stage
00508          if ( NZ != ReferenceNZ )
00509          {
00510             vtkErrorMacro(<< "File is not coherent in Z with previous ones"
00511                            << filename->c_str());
00512          }
00513          else
00514          {
00515             vtkDebugMacro(<< "File is coherent with previous ones"
00516                            << filename->c_str());
00517          }
00518 
00519          // Stage 2.3: when the file contains a volume (as opposed to an image),
00520          // notify the caller.
00521          if (NZ > 1)
00522          {
00523             vtkErrorMacro(<< "This file contains multiple planes (images)"
00524                            << filename->c_str());
00525          }
00526 
00527          // Eventually, this file can be added on the stack. Update the
00528          // full size of the stack
00529          vtkDebugMacro("Number of planes added to the stack: " << NZ);
00530          ReturnedTotalNumberOfPlanes += NZ - 1; // First plane already added
00531          continue;
00532 
00533       } 
00534       else 
00535       {
00536          // We didn't have a workable reference file yet. Set this one
00537          // as the reference.
00538          FoundReferenceFile = true;
00539          vtkDebugMacro(<< "This file taken as coherence reference:"
00540                         << filename->c_str());
00541          vtkDebugMacro(<< "Image dimension of reference file as read from Gdcm:" 
00542                         << NX << " " << NY << " " << NZ);
00543          vtkDebugMacro(<< "Number of planes added to the stack: " << NZ);
00544          // Set aside the size of the image
00545          this->NumColumns = NX;
00546          this->NumLines   = NY;
00547          ReferenceNZ      = NZ;
00548          ReturnedTotalNumberOfPlanes += NZ - 1; // First plane already added
00549          this->ImageType = type;
00550          this->PixelSize = GdcmFile.GetPixelSize();
00551 
00552          if( GdcmFile.HasLUT() && this->AllowLookupTable )
00553          {
00554             // I could raise an error is AllowLookupTable is on and HasLUT() off
00555             this->NumComponents = GdcmFile.GetNumberOfScalarComponentsRaw();
00556          }
00557          else
00558          {
00559             this->NumComponents = GdcmFile.GetNumberOfScalarComponents(); //rgb or mono
00560          }
00561        
00562          //Set image spacing
00563          this->DataSpacing[0] = GdcmFile.GetXSpacing();
00564          this->DataSpacing[1] = GdcmFile.GetYSpacing();
00565          this->DataSpacing[2] = GdcmFile.GetZSpacing();
00566 
00567          //Set image origin
00568          //this->DataOrigin[0] = GdcmFile.GetXOrigin();
00569          //this->DataOrigin[1] = GdcmFile.GetYOrigin();
00570          //this->DataOrigin[2] = GdcmFile.GetZOrigin();
00571 
00572       }
00573    } // End of loop on filename
00574 
00576    // count the loadable number of files and display their number:
00577    int NumberCoherentFiles = 0;
00578    for (std::list<std::string>::iterator it = InternalFileNameList.begin();
00579         it != InternalFileNameList.end();
00580         ++it)
00581    {
00582       if (*it != "GDCM_UNREADABLE")
00583       {
00584          NumberCoherentFiles++;
00585       }
00586    }
00587    vtkDebugMacro(<< "Number of coherent files: " << NumberCoherentFiles);
00588 
00589    if (ReturnedTotalNumberOfPlanes == 0)
00590    {
00591       vtkErrorMacro(<< "No loadable file.");
00592    }
00593 
00594    vtkDebugMacro(<< "Total number of planes on the stack: "
00595                   << ReturnedTotalNumberOfPlanes);
00596    
00597    return ReturnedTotalNumberOfPlanes;
00598 }
00599 
00600 //-----------------------------------------------------------------------------
00601 // Private
00602 /*
00603  * Remove all file names to the internal list of images to read.
00604  */
00605 void vtkGdcmReader::RemoveAllInternalFileName(void)
00606 {
00607    this->InternalFileNameList.clear();
00608 }
00609 
00610 /*
00611  * Adds a file name to the internal list of images to read.
00612  */
00613 void vtkGdcmReader::AddInternalFileName(const char* name)
00614 {
00615    char * LocalName = new char[strlen(name) + 1];
00616    strcpy(LocalName, name);
00617    this->InternalFileNameList.push_back(LocalName);
00618    delete[] LocalName;
00619 }
00620 
00621 /*
00622  * Loads the contents of the image/volume contained by Filename at
00623  * the Dest memory address. Returns the size of the data loaded.
00624  */
00625 size_t vtkGdcmReader::LoadImageInMemory(
00626              std::string fileName, 
00627              unsigned char *dest,
00628              const unsigned long updateProgressTarget,
00629              unsigned long & updateProgressCount)
00630 {
00631    vtkDebugMacro(<< "Copying to memory image [" << fileName.c_str() << "]");
00632    gdcm::FileHelper file( fileName.c_str() );
00633    size_t size;
00634 
00635    // If the data structure of vtk for image/volume representation
00636    // were straigthforwards the following would be enough:
00637    //    GdcmFile.GetImageDataIntoVector((void*)Dest, size);
00638    // But vtk chooses to invert the lines of an image, that is the last
00639    // line comes first (for some axis related reasons?). Hence we need
00640    // to load the image line by line, starting from the end.
00641 
00642    int numColumns = file.GetFile()->GetXSize();
00643    int numLines   = file.GetFile()->GetYSize();
00644    int numPlanes  = file.GetFile()->GetZSize();
00645    int lineSize   = NumComponents * numColumns * file.GetFile()->GetPixelSize();
00646    int planeSize  = lineSize * numLines;
00647 
00648    unsigned char *src;
00649    
00650    if( file.GetFile()->HasLUT() && AllowLookupTable )
00651    {
00652       size               = file.GetImageDataSize();
00653       src                = (unsigned char*) file.GetImageDataRaw();
00654       unsigned char *lut = (unsigned char*) file.GetLutRGBA();
00655 
00656       if(!this->LookupTable)
00657       {
00658          this->LookupTable = vtkLookupTable::New();
00659       }
00660 
00661       this->LookupTable->SetNumberOfTableValues(256);
00662       for (int tmp=0; tmp<256; tmp++)
00663       {
00664          this->LookupTable->SetTableValue(tmp,
00665          (float)lut[4*tmp+0]/255.0,
00666          (float)lut[4*tmp+1]/255.0,
00667          (float)lut[4*tmp+2]/255.0,
00668          1);
00669       }
00670       this->LookupTable->SetRange(0,255);
00671       vtkDataSetAttributes *a = this->GetOutput()->GetPointData();
00672       a->GetScalars()->SetLookupTable(this->LookupTable);
00673       free(lut);
00674    }
00675    else
00676    {
00677       size = file.GetImageDataSize();
00678       src  = (unsigned char*)file.GetImageData();
00679    } 
00680 
00681    unsigned char *dst = dest + planeSize - lineSize;
00682    for (int plane = 0; plane < numPlanes; plane++)
00683    {
00684       for (int line = 0; line < numLines; line++)
00685       {
00686          // Copy one line at proper destination:
00687          memcpy((void*)dst, (void*)src, lineSize);
00688          src += lineSize;
00689          dst -= lineSize;
00690          // Update progress related:
00691          if (!(updateProgressCount%updateProgressTarget))
00692          {
00693             this->UpdateProgress(updateProgressCount/(50.0*updateProgressTarget));
00694          }
00695          updateProgressCount++;
00696       }
00697       dst += 2 * planeSize;
00698    }
00699    
00700    return size;
00701 }
00702 
00703 //-----------------------------------------------------------------------------

Generated on Thu Feb 10 22:18:01 2005 for gdcm by doxygen 1.3.6