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