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