+
+/**
+ * Load all the files and set it in the InternalFileList
+ * For each file, the readability and the coherence of image caracteristics
+ * are tested. If an image doesn't agree the required specifications, it
+ * isn't considered and no data will be set for the planes corresponding
+ * to this image
+ *
+ * The source of this work is the list of file name generated by the
+ * BuildFileListFromPattern method
+ */
+void vtkGdcmReader::LoadFileInformation()
+{
+ GDCM_NAME_SPACE::File *file;
+ bool foundReference=false;
+ std::string type;
+
+ this->OwnFile=true;
+ for (std::list<std::string>::iterator filename = InternalFileNameList.begin();
+ filename != InternalFileNameList.end();
+ ++filename)
+ {
+ // check for file readability
+ FILE *fp;
+ fp = fopen(filename->c_str(),"rb");
+ if (!fp)
+ {
+ vtkErrorMacro(<< "Unable to open file " << filename->c_str());
+ vtkErrorMacro(<< "Removing this file from read files: "
+ << filename->c_str());
+ file = NULL;
+ InternalFileList.push_back(file);
+ continue;
+ }
+ fclose(fp);
+
+ // Read the file
+ file=GDCM_NAME_SPACE::File::New();
+ file->SetLoadMode( LoadMode );
+ file->SetFileName(filename->c_str() );
+ file->Load();
+
+ // Test the Dicom file readability
+ if(!file->IsReadable())
+ {
+ vtkErrorMacro(<< "Gdcm cannot parse file " << filename->c_str());
+ vtkErrorMacro(<< "Removing this file from read files: "
+ << filename->c_str());
+ file->Delete();
+ file=NULL;
+ InternalFileList.push_back(file);
+ continue;
+ }
+
+ // Test the Pixel Type recognition
+ type = file->GetPixelType();
+ if ( (type != "8U") && (type != "8S")
+ && (type != "16U") && (type != "16S")
+ && (type != "32U") && (type != "32S") )
+ {
+ vtkErrorMacro(<< "Bad File Type for file " << filename->c_str() << "\n"
+ << " File type found : " << type.c_str()
+ << " (might be 8U, 8S, 16U, 16S, 32U, 32S) \n"
+ << " Removing this file from read files");
+ file->Delete();
+ file=NULL;
+ InternalFileList.push_back(file);
+ continue;
+ }
+
+ // Test the image informations
+ if(!foundReference)
+ {
+ foundReference = true;
+ GetFileInformation(file);
+
+ vtkDebugMacro(<< "This file taken as coherence reference:"
+ << filename->c_str());
+ vtkDebugMacro(<< "Image dimensions of reference file as read from Gdcm:"
+ << this->NumColumns << " " << this->NumLines << " "
+ << this->NumPlanes);
+ }
+ else if(!TestFileInformation(file))
+ {
+ file->Delete();
+ file=NULL;
+ }
+
+ InternalFileList.push_back(file);
+ }
+}
+
+/**
+ * Update the file informations.
+ * This works exactly like LoadFileInformation, but the source of work
+ * is the list of coherent files
+ */
+void vtkGdcmReader::UpdateFileInformation()
+{
+ this->InternalFileList=*(this->CoherentFileList);
+ this->OwnFile=false;
+
+ for(gdcmFileList::iterator it=InternalFileList.begin();
+ it!=InternalFileList.end();
+ ++it)
+ {
+ if( *it != NULL)
+ {
+ GetFileInformation(*it);
+ break;
+ }
+ }
+}
+
+/**
+ * Get the informations from a file.
+ * These informations are required to specify the output image
+ * caracteristics
+ */
+void vtkGdcmReader::GetFileInformation(GDCM_NAME_SPACE::File *file)
+{
+ // Get the image caracteristics
+ this->NumColumns = file->GetXSize();
+ this->NumLines = file->GetYSize();
+ this->NumPlanes = file->GetZSize();
+
+ if (CoherentFileList == 0)
+ this->TotalNumberOfPlanes = this->NumPlanes*InternalFileNameList.size();
+ else
+ this->TotalNumberOfPlanes = this->NumPlanes*CoherentFileList->size();
+
+ this->ImageType = file->GetPixelType();
+ this->PixelSize = file->GetPixelSize();
+
+ this->DataSpacing[0] = file->GetXSpacing();
+ this->DataSpacing[1] = file->GetYSpacing();
+
+ // Most of the file headers have NO z spacing
+ // It must be calculated from the whole GDCM_NAME_SPACE::Serie (if any)
+ // using Jolinda Smith's algoritm.
+ // see GDCM_NAME_SPACE::SerieHelper::ImagePositionPatientOrdering()
+ if (CoherentFileList == 0)
+ this->DataSpacing[2] = file->GetZSpacing();
+ else
+ {
+ // Just because OrderFileList() is a member of GDCM_NAME_SPACE::SerieHelper
+ // we need to instanciate sh.
+ GDCM_NAME_SPACE::SerieHelper *sh = GDCM_NAME_SPACE::SerieHelper::New();
+ sh->OrderFileList(CoherentFileList); // calls ImagePositionPatientOrdering()
+ this->DataSpacing[2] = sh->GetZSpacing();
+ sh->Delete();
+ }
+
+ // Get the image data caracteristics
+ if( file->HasLUT() && this->AllowLookupTable )
+ {
+ // I could raise an error is AllowLookupTable is on and HasLUT() off
+ this->NumComponents = file->GetNumberOfScalarComponentsRaw();
+ }
+ else
+ {
+ this->NumComponents = file->GetNumberOfScalarComponents(); //rgb or mono
+ }
+}
+
+/*
+ * When more than one filename is specified (i.e. we expect loading
+ * a stack or volume) we need to check that the corresponding images/volumes
+ * to be loaded are coherent i.e. to make sure:
+ * - they all share the same X dimensions
+ * - they all share the same Y dimensions
+ * - they all share the same ImageType ( 8 bit signed, or unsigned...)
+ *
+ * Eventually, we emit a warning when all the files do NOT share the
+ * Z dimension, since we can still build a stack but the
+ * files are not coherent in Z, which is probably a source a trouble...
+ * When files are not readable (either the file cannot be opened or
+ * because gdcm cannot parse it), they are flagged as "GDCM_UNREADABLE".
+ * This method returns the total number of planar images to be loaded
+ * (i.e. an image represents one plane, but a volume represents many planes)
+ */
+/**
+ * Test the coherent informations of the file with the reference informations
+ * used as image caracteristics. The tested informations are :
+ * - they all share the same X dimensions
+ * - they all share the same Y dimensions
+ * - they all share the same Z dimensions
+ * - they all share the same number of components
+ * - they all share the same ImageType ( 8 bit signed, or unsigned...)
+ *
+ * \return True if the file match, False otherwise
+ */
+bool vtkGdcmReader::TestFileInformation(GDCM_NAME_SPACE::File *file)
+{
+ int numColumns = file->GetXSize();
+ int numLines = file->GetYSize();
+ int numPlanes = file->GetZSize();
+ int numComponents;
+ unsigned int pixelSize = file->GetPixelSize();
+
+ if( file->HasLUT() && this->AllowLookupTable )
+ numComponents = file->GetNumberOfScalarComponentsRaw();
+ else
+ numComponents = file->GetNumberOfScalarComponents(); //rgb or mono
+
+ if( numColumns != this->NumColumns )
+ {
+ vtkErrorMacro(<< "File X value doesn't match with the previous ones: "
+ << file->GetFileName().c_str()
+ << ". Found " << numColumns << ", must be "
+ << this->NumColumns);
+ return false;
+ }
+ if( numLines != this->NumLines )
+ {
+ vtkErrorMacro(<< "File Y value doesn't match with the previous ones: "
+ << file->GetFileName().c_str()
+ << ". Found " << numLines << ", must be "
+ << this->NumLines);
+ return false;
+ }
+ if( numPlanes != this->NumPlanes )
+ {
+ vtkErrorMacro(<< "File Z value doesn't match with the previous ones: "
+ << file->GetFileName().c_str()
+ << ". Found " << numPlanes << ", must be "
+ << this->NumPlanes);
+ return false;
+ }
+ if( numComponents != this->NumComponents )
+ {
+ vtkErrorMacro(<< "File Components count doesn't match with the previous ones: "
+ << file->GetFileName().c_str()
+ << ". Found " << numComponents << ", must be "
+ << this->NumComponents);
+ return false;
+ }
+ if( pixelSize != this->PixelSize )
+ {
+ vtkErrorMacro(<< "File pixel size doesn't match with the previous ones: "
+ << file->GetFileName().c_str()
+ << ". Found " << pixelSize << ", must be "
+ << this->PixelSize);
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Private
+/*
+ * Remove all file names to the internal list of images to read.
+ */
+void vtkGdcmReader::RemoveAllInternalFileName(void)
+{
+ this->InternalFileNameList.clear();
+}
+
+/*
+ * Adds a file name to the internal list of images to read.
+ */
+void vtkGdcmReader::AddInternalFileName(const char *name)
+{
+ char *LocalName = new char[strlen(name) + 1];
+ strcpy(LocalName, name);
+ this->InternalFileNameList.push_back(LocalName);
+ delete[] LocalName;
+}
+
+/*
+ * Remove all file names to the internal list of images to read.
+ */
+void vtkGdcmReader::RemoveAllInternalFile(void)
+{
+ if(this->OwnFile)
+ {
+ for(gdcmFileList::iterator it=InternalFileList.begin();
+ it!=InternalFileList.end();
+ ++it)
+ {
+ (*it)->Delete();
+ }
+ }
+ this->InternalFileList.clear();
+}
+
+void vtkGdcmReader::IncrementProgress(const unsigned long updateProgressTarget,
+ unsigned long &updateProgressCount)
+{
+ // Update progress related for bad files:
+ updateProgressCount += this->NumLines;
+ if (updateProgressTarget > 0)
+ {
+ if (!(updateProgressCount%updateProgressTarget))
+ {
+ this->UpdateProgress(
+ updateProgressCount/(50.0*updateProgressTarget));
+ }
+ }
+}
+
+/*
+ * Loads the contents of the image/volume contained by char *fileName at
+ * the dest memory address. Returns the size of the data loaded.
+ */
+/*void vtkGdcmReader::LoadImageInMemory(
+ std::string fileName,
+ unsigned char *dest,
+ const unsigned long updateProgressTarget,
+ unsigned long &updateProgressCount)
+{
+ vtkDebugMacro(<< "Copying to memory image [" << fileName.c_str() << "]");
+
+ GDCM_NAME_SPACE::File *f;
+ f = new GDCM_NAME_SPACE::File();
+ f->SetLoadMode( LoadMode );
+ f->SetFileName( fileName.c_str() );
+ f->Load( );
+
+ LoadImageInMemory(f,dest,
+ updateProgressTarget,
+ updateProgressCount);
+ delete f;
+}*/
+
+/*
+ * Loads the contents of the image/volume contained by GDCM_NAME_SPACE::File* f at
+ * the Dest memory address. Returns the size of the data loaded.
+ * \ param f File to consider. NULL if the file must be skiped
+ * \remarks Assume that if (f != NULL) then its caracteristics match
+ * with the previous ones
+ */
+void vtkGdcmReader::LoadImageInMemory(
+ GDCM_NAME_SPACE::File *f,
+ unsigned char *dest,
+ const unsigned long updateProgressTarget,
+ unsigned long &updateProgressCount)
+{
+ if(!f)
+ return;
+
+ GDCM_NAME_SPACE::FileHelper *fileH = GDCM_NAME_SPACE::FileHelper::New( f );
+ fileH->SetUserFunction( UserFunction );
+
+ fileH->SetKeepOverlays ( this->KeepOverlays);
+
+ int numColumns = f->GetXSize();
+ int numLines = f->GetYSize();
+ int numPlanes = f->GetZSize();
+ int numComponents;
+
+ if( f->HasLUT() && this->AllowLookupTable )
+ numComponents = f->GetNumberOfScalarComponentsRaw();
+ else
+ numComponents = f->GetNumberOfScalarComponents(); //rgb or mono
+ vtkDebugMacro(<< "numComponents:" << numComponents);
+ vtkDebugMacro(<< "Copying to memory image [" << f->GetFileName().c_str() << "]");
+ //size_t size;
+
+ // If the data structure of vtk for image/volume representation
+ // were straigthforwards the following would be enough:
+ // GdcmFile.GetImageDataIntoVector((void*)Dest, size);
+ // But vtk chooses to invert the lines of an image, that is the last
+ // line comes first (for some axis related reasons?). Hence we need
+ // to load the image line by line, starting from the end.
+
+ int lineSize = NumComponents * numColumns * f->GetPixelSize();
+ int planeSize = lineSize * numLines;
+
+ unsigned char *src;
+
+ if( fileH->GetFile()->HasLUT() && AllowLookupTable )
+ {
+ // to avoid bcc 5.5 w
+ /*size = */ fileH->GetImageDataSize();
+ src = (unsigned char*) fileH->GetImageDataRaw();
+ unsigned char *lut = (unsigned char*) fileH->GetLutRGBA();
+
+ if(!this->LookupTable)
+ {
+ this->LookupTable = vtkLookupTable::New();
+ }
+
+ this->LookupTable->SetNumberOfTableValues(256);
+ for (int tmp=0; tmp<256; tmp++)
+ {
+ this->LookupTable->SetTableValue(tmp,
+ (float)lut[4*tmp+0]/255.0,
+ (float)lut[4*tmp+1]/255.0,
+ (float)lut[4*tmp+2]/255.0,
+ 1);
+ }
+ this->LookupTable->SetRange(0,255);
+ vtkDataSetAttributes *a = this->GetOutput()->GetPointData();
+ a->GetScalars()->SetLookupTable(this->LookupTable);
+ free(lut);
+ }
+ else
+ {
+ //size = fileH->GetImageDataSize();
+ // useless - just an accessor; 'size' unused
+ src = (unsigned char*)fileH->GetImageData();
+ }
+
+ unsigned char *dst = dest + planeSize - lineSize;
+ for (int plane = 0; plane < numPlanes; plane++)
+ {
+ for (int line = 0; line < numLines; line++)
+ {
+ // Copy one line at proper destination:
+ memcpy((void*)dst, (void*)src, lineSize);
+ src += lineSize;
+ dst -= lineSize;
+ // Update progress related:
+ if (!(updateProgressCount%updateProgressTarget))
+ {
+ this->UpdateProgress(
+ updateProgressCount/(50.0*updateProgressTarget));
+ }
+ updateProgressCount++;
+ }
+ dst += 2 * planeSize;
+ }
+
+ fileH->Delete();
+}
+
+//-----------------------------------------------------------------------------