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