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