]> Creatis software - gdcm.git/blob - vtk/vtkGdcmReader.cxx
vtkGdcmReader has now a new method SetLoadMode, to allow user to specify what he
[gdcm.git] / vtk / vtkGdcmReader.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: vtkGdcmReader.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/06/29 16:12:43 $
7   Version:   $Revision: 1.72 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18                                                                                 
19 //-----------------------------------------------------------------------------
20 // //////////////////////////////////////////////////////////////
21 // WARNING TODO CLEANME 
22 // Actual limitations of this code:
23 //
24 // /////// Redundant and unnecessary header parsing
25 // In it's current state this code actually parses three times the Dicom
26 // header of a file before the corresponding image gets loaded in the
27 // ad-hoc vtkData !
28 // Here is the process:
29 //  1/ First loading happens in ExecuteInformation which, in order to
30 //     positionate the vtk extents, calls CheckFileCoherence. The purpose
31 //     of CheckFileCoherence is to make sure all the images in the future
32 //     stack are "homogenous" (same size, same representation...).
33 //     This can only be achieved by parsing all the Dicom headers...
34 //     --> to avoid loosing too much time :
35 //     If user is 150% sure *all* the files are coherent, that is to say :
36 //     they may be open, they are gdcm-readable, they have the same sizes,
37 //     they have the same 'pixel' type, they are single frame, 
38 //     they have the same color convention ...
39 //     he may use SetCheckFileCoherenceLight() to request a 'light' coherence
40 //     checking
41 //  2/ ExecuteData is then responsible for the next two loadings - 2 ?!?-:
42 //  2a/ ExecuteData calls AllocateOutputData that in turn seems to 
43 //      (indirectely call) ExecuteInformation which ends up in a second
44 //      header parsing
45 //      This is fixed by adding a test at the beginning of ExecuteInformation
46 //      on the modification of the object instance. If a modification have been
47 //      made (method Modified() ), the MTime value is increased. The fileTime
48 //      is compared to this new value to find a modification in the class
49 //      parameters
50 //  2b/ the core of ExecuteData then needs gdcmFile (which in turns
51 //      initialises gdcmFile in the constructor) in order to access
52 //      the data-image.
53 //
54 // Possible solution:
55 // maintain a list of gdcmFiles (created by say ExecuteInformation) created
56 // once and for all accross the life of vtkGdcmFile (it would only load
57 // new gdcmFile if the user changes the list). ExecuteData would then use 
58 // those gdcmFile and hence avoid calling the construtor:
59 //  - advantage: the header of the files would only be parser once.
60 //  - drawback: once execute information is called (i.e. on creation of
61 //              a vtkGdcmFile) the gdcmFile structure is loaded in memory.
62 //              The average size of a gdcm::File being of 100Ko, 
63 //              - 100 Ko ? Better say 1 Mo; we are in 2005 ! - 
64 //              if oneloads 10 stacks of images with say 200 images each,
65 //              you end-up with a loss of 200Mo...
66 //
67 // /////// Never unallocated memory:
68 // ExecuteData allocates space for the pixel data [which will get pointed
69 // by the vtkPointData() through the call
70 // data->GetPointData()->GetScalars()->SetVoidArray(mem, StackNumPixels, 0);]
71 // This data is never "freed" neither in the destructor nor when the
72 // filename list is extended, ExecuteData is called a second (or third)
73 // time...
74 // //////////////////////////////////////////////////////////////
75
76 #include "gdcmFileHelper.h"
77 #include "gdcmFile.h"
78 #include "gdcmDocument.h"  // for NO_SEQ
79
80 #include "vtkGdcmReader.h"
81 #include "gdcmDebug.h"
82
83 //#include <stdio.h>
84 #include <vtkObjectFactory.h>
85 #include <vtkImageData.h>
86 #include <vtkPointData.h>
87 #include <vtkLookupTable.h>
88
89 vtkCxxRevisionMacro(vtkGdcmReader, "$Revision: 1.72 $");
90 vtkStandardNewMacro(vtkGdcmReader);
91
92 //-----------------------------------------------------------------------------
93 // Constructor / Destructor
94 vtkGdcmReader::vtkGdcmReader()
95 {
96    this->LookupTable = NULL;
97    this->AllowLookupTable = 0;
98    this->LightChecking = false;
99    this->LoadMode = 0; // Load everything (possible values : NO_SEQ, NO_SHADOW
100                        //                                    NO_SHADOWSEQ)
101 }
102
103 vtkGdcmReader::~vtkGdcmReader()
104 {
105    this->RemoveAllFileName();
106    this->InternalFileNameList.clear();
107    if(this->LookupTable) 
108       this->LookupTable->Delete();
109 }
110
111 //-----------------------------------------------------------------------------
112 // Print
113 void vtkGdcmReader::PrintSelf(ostream &os, vtkIndent indent)
114 {
115    this->Superclass::PrintSelf(os,indent);
116    os << indent << "Filenames  : " << endl;
117    vtkIndent nextIndent = indent.GetNextIndent();
118    for (std::list<std::string>::iterator it = FileNameList.begin();
119         it != FileNameList.end();
120         ++it)
121    {
122       os << nextIndent << it->c_str() << endl ;
123    }
124 }
125
126 //-----------------------------------------------------------------------------
127 // Public
128 /*
129  * Remove all files from the list of images to read.
130  */
131 void vtkGdcmReader::RemoveAllFileName(void)
132 {
133    this->FileNameList.clear();
134    this->Modified();
135 }
136
137 /*
138  * Adds a file name to the list of images to read.
139  */
140 void vtkGdcmReader::AddFileName(const char* name)
141 {
142    // We need to bypass the const pointer [since list<>.push_bash() only
143    // takes a char* (but not a const char*)] by making a local copy:
144    char *LocalName = new char[strlen(name) + 1];
145    strcpy(LocalName, name);
146    this->FileNameList.push_back(LocalName);
147    delete[] LocalName;
148    this->Modified();
149 }
150
151 /*
152  * Sets up a filename to be read.
153  */
154 void vtkGdcmReader::SetFileName(const char *name) 
155 {
156    vtkImageReader2::SetFileName(name);
157    // Since we maintain a list of filenames, when building a volume,
158    // (see vtkGdcmReader::AddFileName), we additionaly need to purge
159    // this list when we manually positionate the filename.
160    vtkDebugMacro(<< "Clearing all files given with AddFileName");
161    this->FileNameList.clear();
162    this->Modified();
163 }
164
165 /*
166  * Ask for a 'light' checking -actually : just initializing-
167  *if you are 150% sure *all* the files are coherent
168  */
169 void vtkGdcmReader::SetCheckFileCoherenceLight()
170 {
171    LightChecking = true;
172 }
173
174 //-----------------------------------------------------------------------------
175 // Protected
176 /*
177  * Configure the output e.g. WholeExtent, spacing, origin, scalar type...
178  */
179 void vtkGdcmReader::ExecuteInformation()
180 {
181    if(this->MTime>this->fileTime)
182    {
183       if ( this->LightChecking )
184          this->TotalNumberOfPlanes = this->CheckFileCoherenceLight();
185       else
186           this->TotalNumberOfPlanes = this->CheckFileCoherence();
187
188       if ( this->TotalNumberOfPlanes == 0)
189       {
190          vtkErrorMacro(<< "File set is not coherent. Exiting...");
191          return;
192       }
193       
194       // if the user has not set the extent, but has set the VOI
195       // set the z axis extent to the VOI z axis
196       if (this->DataExtent[4]==0 && this->DataExtent[5] == 0 &&
197       (this->DataVOI[4] || this->DataVOI[5]))
198       {
199          this->DataExtent[4] = this->DataVOI[4];
200          this->DataExtent[5] = this->DataVOI[5];
201       }
202
203       // When the user has set the VOI, check it's coherence with the file content.
204       if (this->DataVOI[0] || this->DataVOI[1] || 
205       this->DataVOI[2] || this->DataVOI[3] ||
206       this->DataVOI[4] || this->DataVOI[5])
207       { 
208          if ((this->DataVOI[0] < 0) ||
209              (this->DataVOI[1] >= this->NumColumns) ||
210              (this->DataVOI[2] < 0) ||
211              (this->DataVOI[3] >= this->NumLines) ||
212              (this->DataVOI[4] < 0) ||
213              (this->DataVOI[5] >= this->TotalNumberOfPlanes ))
214          {
215             vtkWarningMacro(<< "The requested VOI is larger than expected extent.");
216             this->DataVOI[0] = 0;
217             this->DataVOI[1] = this->NumColumns - 1;
218             this->DataVOI[2] = 0;
219             this->DataVOI[3] = this->NumLines - 1;
220             this->DataVOI[4] = 0;
221             this->DataVOI[5] = this->TotalNumberOfPlanes - 1;
222          }
223       }
224
225       // Positionate the Extent.
226       this->DataExtent[0] = 0;
227       this->DataExtent[1] = this->NumColumns - 1;
228       this->DataExtent[2] = 0;
229       this->DataExtent[3] = this->NumLines - 1;
230       this->DataExtent[4] = 0;
231       this->DataExtent[5] = this->TotalNumberOfPlanes - 1;
232   
233       // We don't need to positionate the Endian related stuff (by using
234       // this->SetDataByteOrderToBigEndian() or SetDataByteOrderToLittleEndian()
235       // since the reading of the file is done by gdcm.
236       // But we do need to set up the data type for downstream filters:
237       if      ( ImageType == "8U" )
238       {
239          vtkDebugMacro(<< "8 bits unsigned image");
240          this->SetDataScalarTypeToUnsignedChar(); 
241       }
242       else if ( ImageType == "8S" )
243       {
244          vtkErrorMacro(<< "Cannot handle 8 bit signed files");
245          return;
246       }
247       else if ( ImageType == "16U" )
248       {
249          vtkDebugMacro(<< "16 bits unsigned image");
250          this->SetDataScalarTypeToUnsignedShort();
251       }
252       else if ( ImageType == "16S" )
253       {
254          vtkDebugMacro(<< "16 bits signed image");
255          this->SetDataScalarTypeToShort();
256       }
257       else if ( ImageType == "32U" )
258       {
259          vtkDebugMacro(<< "32 bits unsigned image");
260          vtkDebugMacro(<< "WARNING: forced to signed int !");
261          this->SetDataScalarTypeToInt();
262       }
263       else if ( ImageType == "32S" )
264       {
265          vtkDebugMacro(<< "32 bits signed image");
266          this->SetDataScalarTypeToInt();
267       }
268       else if ( ImageType == "FD" )
269       {
270          vtkDebugMacro(<< "64 bits Double image");
271          this->SetDataScalarTypeToDouble();
272       }
273       //Set number of scalar components:
274       this->SetNumberOfScalarComponents(this->NumComponents);
275
276       this->fileTime=this->MTime;
277    }
278
279    this->Superclass::ExecuteInformation();
280 }
281
282 /*
283  * Update => ouput->Update => UpdateData => Execute => ExecuteData 
284  * (see vtkSource.cxx for last step).
285  * This function (redefinition of vtkImageReader::ExecuteData, see 
286  * VTK/IO/vtkImageReader.cxx) reads a data from a file. The data
287  * extent/axes are assumed to be the same as the file extent/order.
288  */
289 void vtkGdcmReader::ExecuteData(vtkDataObject *output)
290 {
291    if (this->InternalFileNameList.empty())
292    {
293       vtkErrorMacro(<< "A least a valid FileName must be specified.");
294       return;
295    }
296
297    // FIXME : extraneous parsing of header is made when allocating OuputData
298    //         --> ?!?
299    vtkImageData *data = this->AllocateOutputData(output);
300    data->SetExtent(this->DataExtent);
301    data->GetPointData()->GetScalars()->SetName("DicomImage-Volume");
302
303    // Test if output has valid extent
304    // Prevent memory errors
305    if((this->DataExtent[1]-this->DataExtent[0]>=0) &&
306       (this->DataExtent[3]-this->DataExtent[2]>=0) &&
307       (this->DataExtent[5]-this->DataExtent[4]>=0))
308    {
309       // The memory size for a full stack of images of course depends
310       // on the number of planes and the size of each image:
311       //size_t StackNumPixels = this->NumColumns * this->NumLines
312       //                      * this->TotalNumberOfPlanes * this->NumComponents;
313       //size_t stack_size = StackNumPixels * this->PixelSize; //not used
314       // Allocate pixel data space itself.
315
316       // Variables for the UpdateProgress. We shall use 50 steps to signify
317       // the advance of the process:
318       unsigned long UpdateProgressTarget = (unsigned long) ceil (this->NumLines
319                                          * this->TotalNumberOfPlanes
320                                          / 50.0);
321       // The actual advance measure:
322       unsigned long UpdateProgressCount = 0;
323
324       // Filling the allocated memory space with each image/volume:
325       unsigned char *Dest = (unsigned char *)data->GetScalarPointer();
326       for (std::list<std::string>::iterator filename  = InternalFileNameList.begin();
327            filename != InternalFileNameList.end();
328            ++filename)
329       { 
330          // Images that were tagged as unreadable in CheckFileCoherence()
331          // are substituted with a black image to let the caller visually
332          // notice something wrong is going on:
333          if (*filename != "GDCM_UNREADABLE")
334          {
335             // Update progress related for good files is made in LoadImageInMemory
336             Dest += this->LoadImageInMemory(*filename, Dest,
337                                             UpdateProgressTarget,
338                                             UpdateProgressCount);
339          } 
340          else 
341          {
342             // We insert a black image in the stack for the user to be aware that
343             // this image/volume couldn't be loaded. We simply skip one image
344             // size:
345             Dest += this->NumColumns * this->NumLines * this->PixelSize;
346
347             // Update progress related for bad files:
348             UpdateProgressCount += this->NumLines;
349             if (UpdateProgressTarget > 0)
350             {
351                if (!(UpdateProgressCount%UpdateProgressTarget))
352                {
353                   this->UpdateProgress(UpdateProgressCount/(50.0*UpdateProgressTarget));
354                }
355             }
356          } // Else, file not loadable
357       } // Loop on files
358    }
359 }
360
361 /*
362  * vtkGdcmReader can have the file names specified through two ways:
363  * (1) by calling the vtkImageReader2::SetFileName(), SetFilePrefix() and
364  *     SetFilePattern()
365  * (2) By successive calls to vtkGdcmReader::AddFileName()
366  * When the first method was used by caller we need to update the local
367  * filename list
368  */
369 void vtkGdcmReader::BuildFileListFromPattern()
370 {
371    this->RemoveAllInternalFileName();
372
373    if ((! this->FileNameList.empty()) && this->FileName )
374    {
375       vtkErrorMacro(<< "Both AddFileName and SetFileName schemes were used");
376       vtkErrorMacro(<< "No images loaded ! ");
377       return;
378    }
379
380    if ((! this->FileNameList.empty()) && this->FilePrefix )
381    {
382       vtkErrorMacro(<< "Both AddFileName and SetFilePrefix schemes were used");
383       vtkErrorMacro(<< "No images loaded ! ");
384       return;
385    }
386
387    if (this->FileName && this->FilePrefix)
388    {
389       vtkErrorMacro(<< "Both SetFileName and SetFilePrefix schemes were used");
390       vtkErrorMacro(<< "No images loaded ! ");
391       return;
392    }
393
394    if (! this->FileNameList.empty()  )
395    {
396       vtkDebugMacro(<< "Using the AddFileName specified files");
397       this->InternalFileNameList=this->FileNameList;
398       return;
399    }
400
401    if (!this->FileName && !this->FilePrefix)
402    {
403       vtkErrorMacro(<< "FileNames are not set. Either use AddFileName() or");
404       vtkErrorMacro(<< "specify a FileName or FilePrefix.");
405       return;
406    }
407
408    if( this->FileName )
409    {
410       // Single file loading (as given with ::SetFileName()):
411       // Case of multi-frame file considered here
412       this->ComputeInternalFileName(this->DataExtent[4]);
413       vtkDebugMacro(<< "Adding file " << this->InternalFileName);
414       this->AddInternalFileName(this->InternalFileName);
415    }
416    else
417    {
418       // Multi file loading (as given with ::SetFilePattern()):
419       for (int idx = this->DataExtent[4]; idx <= this->DataExtent[5]; ++idx)
420       {
421          this->ComputeInternalFileName(idx);
422          vtkDebugMacro(<< "Adding file " << this->InternalFileName);
423          this->AddInternalFileName(this->InternalFileName);
424       }
425    }
426 }
427
428 /*
429  * When more than one filename is specified (i.e. we expect loading
430  * a stack or volume) we need to check that the corresponding images/volumes
431  * to be loaded are coherent i.e. to make sure:
432  *     - they all share the same X dimensions
433  *     - they all share the same Y dimensions
434  *     - they all share the same ImageType ( 8 bit signed, or unsigned...)
435  *
436  * Eventually, we emit a warning when all the files do NOT share the
437  * Z dimension, since we can still build a stack but the
438  * files are not coherent in Z, which is probably a source a trouble...
439  *   When files are not readable (either the file cannot be opened or
440  * because gdcm cannot parse it), they are flagged as "GDCM_UNREADABLE".  
441  *   This method returns the total number of planar images to be loaded
442  * (i.e. an image represents one plane, but a volume represents many planes)
443  */
444 int vtkGdcmReader::CheckFileCoherence()
445 {
446    int ReturnedTotalNumberOfPlanes = 0;   // The returned value.
447
448    this->BuildFileListFromPattern();
449    if (this->InternalFileNameList.empty())
450    {
451       vtkErrorMacro(<< "FileNames are not set.");
452       return 0;
453    }
454
455    bool FoundReferenceFile = false;
456    int  ReferenceNZ = 0;
457
458    // Loop on the filenames:
459    // - check for their existence and gdcm "parsability"
460    // - get the coherence check done:
461    for (std::list<std::string>::iterator filename = InternalFileNameList.begin();
462         filename != InternalFileNameList.end();
463         ++filename)
464    {
465       // The file is always added in the number of planes
466       //  - If file doesn't exist, it will be replaced by a black plane in the 
467       //    ExecuteData method
468       //  - If file has more than 1 plane, other planes will be added later to
469       //    to the ReturnedTotalNumberOfPlanes variable counter
470       ReturnedTotalNumberOfPlanes += 1;
471
472       /////// Stage 0: check for file name:
473
474       // fixme : how can the filename be equal to "GDCM_UNREADABLE"
475       //         right now ?!?
476
477       if(*filename == std::string("GDCM_UNREADABLE"))
478          continue;
479
480       /////// Stage 1: check for file readability:
481       // Stage 1.1: check for file existence.
482       FILE *fp;
483       fp = fopen(filename->c_str(),"rb");
484       if (!fp)
485       {
486          vtkErrorMacro(<< "Unable to open file " << filename->c_str());
487          vtkErrorMacro(<< "Removing this file from read files: "
488                      << filename->c_str());
489          *filename = "GDCM_UNREADABLE";
490          continue;
491       }
492       fclose(fp);
493
494       // Stage 1.2: check for Gdcm parsability
495
496       //gdcm::File GdcmFile( filename->c_str() );
497       // to save some parsing time.
498       gdcm::File GdcmFile;
499       GdcmFile.SetLoadMode( LoadMode );
500       GdcmFile.Load(filename->c_str() );
501       if (!GdcmFile.IsReadable())
502       {
503          vtkErrorMacro(<< "Gdcm cannot parse file " << filename->c_str());
504          vtkErrorMacro(<< "Removing this file from read files: "
505                         << filename->c_str());
506          *filename = "GDCM_UNREADABLE";
507          continue;
508       }
509
510       // Stage 1.3: further gdcm compatibility on PixelType
511       std::string type = GdcmFile.GetPixelType();
512       if (   (type !=  "8U") && (type !=  "8S")
513           && (type != "16U") && (type != "16S")
514           && (type != "32U") && (type != "32S") )
515       {
516          vtkErrorMacro(<< "Bad File Type for file " << filename->c_str() << "\n"
517                        << "   File type found : " << type.c_str() 
518                        << " (might be 8U, 8S, 16U, 16S, 32U, 32S) \n"
519                        << "   Removing this file from readed files");
520          *filename = "GDCM_UNREADABLE";
521          continue;
522       }
523
524       // Stage 2: check coherence of the set of files
525       int NX = GdcmFile.GetXSize();
526       int NY = GdcmFile.GetYSize();
527       int NZ = GdcmFile.GetZSize();
528       if (FoundReferenceFile) 
529       {
530          // Stage 2.1: mandatory coherence stage:
531          if (   ( NX   != this->NumColumns )
532              || ( NY   != this->NumLines )
533              || ( type != this->ImageType ) ) 
534          {
535             vtkErrorMacro(<< "This file is not coherent with previous ones: "
536                            << filename->c_str());
537             vtkErrorMacro(<< "Removing this file from readed files: "
538                            << filename->c_str());
539             *filename = "GDCM_UNREADABLE";
540             continue;
541          }
542
543          // Stage 2.2: optional coherence stage
544          if ( NZ != ReferenceNZ )
545          {
546             vtkErrorMacro(<< "File is not coherent in Z with previous ones: "
547                            << filename->c_str());
548          }
549          else
550          {
551             vtkDebugMacro(<< "File is coherent with previous ones: "
552                            << filename->c_str());
553          }
554
555          // Stage 2.3: when the file is 'multiframe', notify the caller.
556          if (NZ > 1)
557          {
558             vtkErrorMacro(<< "This file is a 'Multiframe' one: "
559                            << filename->c_str());
560          }
561
562          // Eventually, this file can be added on the stack. Update the
563          // full size of the stack
564          vtkDebugMacro("Number of planes added to the stack: " << NZ);
565          ReturnedTotalNumberOfPlanes += NZ - 1; // First plane already added
566          continue;
567
568       } 
569       else 
570       {
571          // We didn't have a workable reference file yet. 
572          // Set this one as the reference.
573          FoundReferenceFile = true;
574          vtkDebugMacro(<< "This file taken as coherence reference:"
575                        << filename->c_str());
576          vtkDebugMacro(<< "Image dimensions of reference file as read from Gdcm:" 
577                        << NX << " " << NY << " " << NZ);
578          vtkDebugMacro(<< "Number of planes added to the stack: " << NZ);
579          // Set aside the size of the image
580          this->NumColumns = NX;
581          this->NumLines   = NY;
582          ReferenceNZ      = NZ;
583          ReturnedTotalNumberOfPlanes += NZ - 1; // First plane already added
584          this->ImageType = type;
585          this->PixelSize = GdcmFile.GetPixelSize();
586
587          if( GdcmFile.HasLUT() && this->AllowLookupTable )
588          {
589             // I could raise an error is AllowLookupTable is on and HasLUT() off
590             this->NumComponents = GdcmFile.GetNumberOfScalarComponentsRaw();
591          }
592          else
593          {
594             this->NumComponents = GdcmFile.GetNumberOfScalarComponents(); //rgb or mono
595          }             
596          //Set image spacing
597          this->DataSpacing[0] = GdcmFile.GetXSpacing();
598          this->DataSpacing[1] = GdcmFile.GetYSpacing();
599          this->DataSpacing[2] = GdcmFile.GetZSpacing();
600       }
601    } // End of loop on filename
602
603    ///////// The files we CANNOT load are flaged. On debugging purposes
604    // count the loadable number of files and display their number:
605    int NumberCoherentFiles = 0;
606    for (std::list<std::string>::iterator it = InternalFileNameList.begin();
607         it != InternalFileNameList.end();
608         ++it)
609    {
610       if (*it != "GDCM_UNREADABLE")
611       {
612          NumberCoherentFiles++;
613       }
614    }
615    vtkDebugMacro(<< "Number of coherent files: " << NumberCoherentFiles);
616
617    if (ReturnedTotalNumberOfPlanes == 0)
618    {
619       vtkErrorMacro(<< "No loadable file.");
620    }
621
622    vtkDebugMacro(<< "Total number of planes on the stack: "
623                   << ReturnedTotalNumberOfPlanes);
624    
625    return ReturnedTotalNumberOfPlanes;
626 }
627
628 //-----------------------------------------------------------------------------
629 // Private
630 /*
631  * Remove all file names to the internal list of images to read.
632  */
633 void vtkGdcmReader::RemoveAllInternalFileName(void)
634 {
635    this->InternalFileNameList.clear();
636 }
637
638 /*
639  * Adds a file name to the internal list of images to read.
640  */
641 void vtkGdcmReader::AddInternalFileName(const char *name)
642 {
643    char *LocalName = new char[strlen(name) + 1];
644    strcpy(LocalName, name);
645    this->InternalFileNameList.push_back(LocalName);
646    delete[] LocalName;
647 }
648
649 /*
650  * Loads the contents of the image/volume contained by Filename at
651  * the Dest memory address. Returns the size of the data loaded.
652  */
653 size_t vtkGdcmReader::LoadImageInMemory(
654              std::string fileName, 
655              unsigned char *dest,
656              const unsigned long updateProgressTarget,
657              unsigned long &updateProgressCount)
658 {
659    vtkDebugMacro(<< "Copying to memory image [" << fileName.c_str() << "]");
660    gdcm::File *f;
661    f = new gdcm::File();
662    f->SetLoadMode( LoadMode );
663    f->Load( fileName.c_str() );
664
665    gdcm::FileHelper fileH( f );
666    size_t size;
667
668    // If the data structure of vtk for image/volume representation
669    // were straigthforwards the following would be enough:
670    //    GdcmFile.GetImageDataIntoVector((void*)Dest, size);
671    // But vtk chooses to invert the lines of an image, that is the last
672    // line comes first (for some axis related reasons?). Hence we need
673    // to load the image line by line, starting from the end.
674
675    int numColumns = fileH.GetFile()->GetXSize();
676    int numLines   = fileH.GetFile()->GetYSize();
677    int numPlanes  = fileH.GetFile()->GetZSize();
678    int lineSize   = NumComponents * numColumns * fileH.GetFile()->GetPixelSize();
679    int planeSize  = lineSize * numLines;
680
681    unsigned char *src;
682    
683    if( fileH.GetFile()->HasLUT() && AllowLookupTable )
684    {
685       size               = fileH.GetImageDataSize();
686       src                = (unsigned char*) fileH.GetImageDataRaw();
687       unsigned char *lut = (unsigned char*) fileH.GetLutRGBA();
688
689       if(!this->LookupTable)
690       {
691          this->LookupTable = vtkLookupTable::New();
692       }
693
694       this->LookupTable->SetNumberOfTableValues(256);
695       for (int tmp=0; tmp<256; tmp++)
696       {
697          this->LookupTable->SetTableValue(tmp,
698          (float)lut[4*tmp+0]/255.0,
699          (float)lut[4*tmp+1]/255.0,
700          (float)lut[4*tmp+2]/255.0,
701          1);
702       }
703       this->LookupTable->SetRange(0,255);
704       vtkDataSetAttributes *a = this->GetOutput()->GetPointData();
705       a->GetScalars()->SetLookupTable(this->LookupTable);
706       free(lut);
707    }
708    else
709    {
710       size = fileH.GetImageDataSize();
711       src  = (unsigned char*)fileH.GetImageData();
712    } 
713
714    unsigned char *dst = dest + planeSize - lineSize;
715    for (int plane = 0; plane < numPlanes; plane++)
716    {
717       for (int line = 0; line < numLines; line++)
718       {
719          // Copy one line at proper destination:
720          memcpy((void*)dst, (void*)src, lineSize);
721          src += lineSize;
722          dst -= lineSize;
723          // Update progress related:
724          if (!(updateProgressCount%updateProgressTarget))
725          {
726             this->UpdateProgress(updateProgressCount/(50.0*updateProgressTarget));
727          }
728          updateProgressCount++;
729       }
730       dst += 2 * planeSize;
731    }
732    delete f;   
733    return size;
734 }
735
736 // -------------------------------------------------------------------------
737
738 // We assume the use *does* know all the files whose names 
739 //  are in InternalFileNameList exist, may be open, are gdcm-readable
740 //  have the same sizes, have the same 'pixel' type, are single frame
741 //  have the same color convention, ..., anything else ? 
742
743 int vtkGdcmReader::CheckFileCoherenceLight()
744 {
745    std::list<std::string>::iterator filename = InternalFileNameList.begin();
746
747    gdcm::File GdcmFile;
748    GdcmFile.SetLoadMode( LoadMode );
749    GdcmFile.Load(filename->c_str() );
750    if (!GdcmFile.IsReadable())
751    {
752       vtkErrorMacro(<< "Gdcm cannot parse file " << filename->c_str());
753       vtkErrorMacro(<< "you should try vtkGdcmReader::CheckFileCoherence "
754                     << "instead of try vtkGdcmReader::CheckFileCoherenceLight");
755       return 0;
756    }
757    int NX           = GdcmFile.GetXSize();
758    int NY           = GdcmFile.GetYSize();
759    // CheckFileCoherenceLight should be called *only* when user knows
760    // he deals with single frames files.
761    // Z size is then the number of files.
762    int NZ           = InternalFileNameList.size();
763    std::string type = GdcmFile.GetPixelType();
764    vtkDebugMacro(<< "The first file is taken as reference: "
765                  << filename->c_str());
766    vtkDebugMacro(<< "Image dimensions of reference file as read from Gdcm:" 
767                  << NX << " " << NY << " " << NZ);
768    vtkDebugMacro(<< "Number of planes added to the stack: " << NZ);
769    // Set aside the size of the image
770    this->NumColumns = NX;
771    this->NumLines   = NY;
772    this->ImageType  = type;
773    this->PixelSize  = GdcmFile.GetPixelSize();
774
775    if( GdcmFile.HasLUT() && this->AllowLookupTable )
776    {
777       // I could raise an error is AllowLookupTable is on and HasLUT() off
778       this->NumComponents = GdcmFile.GetNumberOfScalarComponentsRaw();
779    }
780    else
781    {
782       this->NumComponents = GdcmFile.GetNumberOfScalarComponents(); //rgb or mono
783    }
784        
785    //Set image spacing
786    this->DataSpacing[0] = GdcmFile.GetXSpacing();
787    this->DataSpacing[1] = GdcmFile.GetYSpacing();
788    this->DataSpacing[2] = GdcmFile.GetZSpacing();
789
790    return InternalFileNameList.size();
791 }
792 //-----------------------------------------------------------------------------