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