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