[Insight-users] IO factory creation problem for writing

Luis Ibanez luis . ibanez at kitware . com
Tue, 18 Jun 2002 17:26:34 -0400


Hi Hans,

Thanks for your feedback,
We are working on the integration of the changes (fixes)
that you proposed. We will be back soon.

Thanks

Luis

===================================================

Hans J. Johnson wrote:

> Hello,
> 
> PROBLEM #1
> ==========
> There is a possible design problem with the way automatic 
> XXXImageIOFactory  works for writing of images.  If you want the 
> ImageFileWriter to determine the output image type automatically, the 
> current implementation may fail.
> The problem is that when itk::ImageFileWriter tries to Write the image, 
> it fails to find a suitable derived class of ImageIOBase.  The failure 
> occurs because the write function calls CreateImageIO, which then calls 
> CanReadFile to determine if it is an accepable derived ImageIOBase is 
> found.  For this to work properly, the CreateImageIO function needs to 
> call CanWriteFile from the class derived from ImageIOBase when doing the 
> Write operation, and CanReadFile when doing the Read operation.
> 
> CALLTREE:
> itk::PNGImageIO::CanReadFile,                                      
> itk::ImageIOFactory::CreateImageIO,                                
> itk::ImageFileWriter<itk::Image<unsigned char,(unsigned int)2> >::Write
> 
> I have attached a simple test to demonstrate this.  Notice that if you 
> first create an image that can be read, then you can use the automatic 
> mechanism to write the image.
> 
> Example outputs from enclosed program:
> 
> [hjohnson@robin FileWriteTest]$ FileWriteTest
> Determining file output type automatically (should be PNG)
> Problem found while writing image ./newtest.png
> Unknown
> itk::ERROR: ImageFileWriter(0x8107db0): No ImageIO set, or none could be 
> created.
> 
> [hjohnson@robin FileWriteTest]$ FileWriteTest "BeExplicit"
> Explicitly setting file output to PNG
> File: ./newtest.png
> Image ./newtest.png Written To Disk
> 
> [hjohnson@robin FileWriteTest]$ FileWriteTest
> Determining file output type automatically (should be PNG)
> File: ./newtest.png
> Image ./newtest.png Written To Disk
> 
> [hjohnson@robin FileWriteTest]$ rm newtest.png
> [hjohnson@robin FileWriteTest]$ FileWriteTest
> Determining file output type automatically (should be PNG)
> Problem found while writing image ./newtest.png
> Unknown
> itk::ERROR: ImageFileWriter(0x8107db0): No ImageIO set, or none could be 
> created.
> 
> SOLUTION:
> ==========
> Replace function called CreateImageIO with function called CreateImageIO 
> Reader,  then duplicate
> that function into one called CreateImageIOWriter that is exactly the 
> same except that it uses CanWriteFile() call instead of CanReadFile() call.
> 
> This change only affects the following four files (including all of the 
> examples):
> ./Code/IO/itkImageIOFactory.h
> ./Code/IO/itkImageIOFactory.cxx
> ./Code/IO/itkImageFileReader.txx
> ./Code/IO/itkImageFileWriter.txx
> 
> patches to implement the described changes are attached to this document.
> 
> 
> PROBLEM #2
> ===========
> PNGImageIO::CanWriteFile(const char * filename)
>       add one line ---> m_FileName=filename;
> SOLUTION
> =========
> Apply patches attached to this e-mail.
> 
> 
> PROBLEM #3
> ===========
> MetaImageIO::Write() not finished
> SOLUTION
> =========
> Finish writing this.  I can do this if it has not yet been done.
> 
> Regards,
> Hans J. Johnson
> hans-johnson@uiowa.edu
> 
> PS:  Is there some other more efficient way to get changes committed to 
> the CVS repository?   Is it possible to get CVS write access?
> 
> PPS:  I have written a file reader for Analyze v7.5 file format.  It has 
> been tested for both reading and writing of images.  If anybody else 
> needs this, just send me an e-mail.
> 
> 
> 
> 
> ------------------------------------------------------------------------
> 
> PROJECT(FileWriteTest)
> 
> # 
> # Find ITK
> #
> FIND_PATH( ITK_BINARY_DIR itkConfigure.h )
> 
> # Load in the values from ITK if found
> IF ( ITK_BINARY_DIR )
>   LOAD_CACHE(${ITK_BINARY_DIR})
>   INCLUDE (${ITK_SOURCE_DIR}/itkCMakeOptions.cmake)
> ENDIF (ITK_BINARY_DIR )
> 
> 
> INCLUDE_DIRECTORIES(
>     ${ITK_SOURCE_DIR}/Code/BasicFilters
>     ${ITK_SOURCE_DIR}/Code/Algorithms
>     ${CMAKE_INSTALL_PREFIX}/include
> )
> 
> LINK_DIRECTORIES(
> ${ITK_BINARY_DIR}/Code/Common
> ${ITK_BINARY_DIR}/Code/IO
>     ${CMAKE_INSTALL_PREFIX}/lib
> )
> 
> LINK_LIBRARIES (
> VXLNumerics
> ITKCommon
> ITKIO
> )
> 
> 
> ADD_EXECUTABLE(FileWriteTest FileWriteTest )
> 
> 
> 
> ------------------------------------------------------------------------
> 
> /*=========================================================================
>   Program:   FileWriteTest
>   Module:    $RCSfile: FileWriteTest.cxx,v $
>   Language:  C++
>   \author Hans J. Johnson
> //  This project is designed to test if you write out an image file 
> //  based on the image extension alone.
> =========================================================================*/
> 
> 
> #include "itkImage.h"
> #include "itkImageFileWriter.h"
> #include "itkImageIOFactory.h"
> #include "itkPNGImageIOFactory.h"
> #include "itkPNGImageIO.h"
> 
> int main(int argc, char *argv[])
> {
>   //Allocate Images
>   enum { ImageDimension = itk::Image<unsigned char,2>::ImageDimension };
>   const itk::Image<unsigned char,2>::SizeType size = {{100,100}};
>   const itk::Image<unsigned char,2>::IndexType index = {{0,0}};
>   itk::Image<unsigned char,2>::RegionType region;
>   region.SetSize( size );
>   region.SetIndex( index );
> 
>   itk::Image<unsigned char,2>::Pointer img = itk::Image<unsigned char,2>::New();
>   img->SetLargestPossibleRegion( region );
>   img->SetBufferedRegion( region );
>   img->SetRequestedRegion( region );
>   img->Allocate();
> 
>   itk::PNGImageIOFactory::RegisterOneFactory();
>   itk::ImageFileWriter<  itk::Image<unsigned char,2>  >::Pointer ImageWriterPointer =  itk::ImageFileWriter<  itk::Image<unsigned char,2>  > ::New();
> 
>     //Set the output filename
>     char outputFileName[] = "./newtest.png";
>     ImageWriterPointer->SetFileName(outputFileName);
>     //Not Necessary if using file extensions to determine. ImageWriterPointer->SetImageIO( Analyzeio );
>     //Make a png image writer
>     itk::PNGImageIO::Pointer pngio;
>     if(argc>1)
>     {
>       std::cout << "Explicitly setting file output to PNG"<< std::endl;
>       pngio= itk::PNGImageIO::New();
>       ImageWriterPointer->SetImageIO( pngio );
>     }
>     else
>     {
>       std::cout << "Determining file output type automatically (should be PNG)"<< std::endl;
>     }
> 
>     //Attach input image to the writer.
>     ImageWriterPointer->SetInput( img );
>     //Determine file type and instantiate appropriate ImageIO class if not
>     //explicitly stated with SetImageIO, then write to disk.
>     try {
>         ImageWriterPointer->Write();
>         std::cout <<" Image "<< outputFileName << " Written To Disk" << std::endl;
>     }
>     catch ( itk::ExceptionObject & ex )
>     {
>         std::string message;
>         message = "Problem found while writing image ";
>         message += outputFileName;
>         message += "\n";
>         message += ex.GetLocation();
>         message += "\n";
>         message += ex.GetDescription();
>         std::cerr << message << std::endl;
>     }
>   return 0;
> }
> 
> 
> ------------------------------------------------------------------------
> 
> --- itkPNGImageIO.h.old	Tue Jun 18 14:04:42 2002
> +++ itkPNGImageIO.h	Tue Jun 18 14:05:20 2002
> @@ -48,7 +48,7 @@
>  
>    /** Determine the file type. Returns true if this ImageIO can read the
>     * file specified. */
> -  virtual bool CanReadFile(const char*);
> +  virtual bool CanReadFile(const char * FileNameToCheck);
>    
>    /** Set the spacing and diemention information for the set filename. */
>    virtual void ReadImageInformation();
> @@ -68,7 +68,7 @@
>  
>    /** Determine the file type. Returns true if this ImageIO can read the
>     * file specified. */
> -  virtual bool CanWriteFile(const char*);
> +  virtual bool CanWriteFile(const char* FileNameToCheck);
>  
>    /** Writes the spacing and dimentions of the image.
>     * Assumes SetFileName has been called with a valid file name. */
> 
> 
> ------------------------------------------------------------------------
> 
> --- itkPNGImageIO.cxx.old	Tue Jun 18 14:04:48 2002
> +++ itkPNGImageIO.cxx	Tue Jun 18 14:06:49 2002
> @@ -41,9 +41,10 @@
>  
>  
>  
> -bool PNGImageIO::CanReadFile(const char* file) 
> -{ 
> -  PNGFileWrapper pngfp(file,"rb");
> +bool PNGImageIO::CanReadFile(const char* FileNameToCheck)
> +{
> +    m_FileName=FileNameToCheck;
> +  PNGFileWrapper pngfp(FileNameToCheck,"rb");
>    FILE* fp = pngfp.m_FilePointer;
>    if(!fp)
>      {
> @@ -367,8 +368,9 @@
>    return;
>  }
>  
> -bool PNGImageIO::CanWriteFile(const char*)
> +bool PNGImageIO::CanWriteFile(const char * FileNameToCheck)
>  {
> +    m_FileName=FileNameToCheck;
>    if ( m_FileName != "" &&
>         m_FileName.find(".png") < m_FileName.length() )
>      {
> 
> 
> ------------------------------------------------------------------------
> 
> --- itkImageIOFactory.h.old	Tue Jun 18 13:36:27 2002
> +++ itkImageIOFactory.h	Tue Jun 18 13:36:27 2002
> @@ -43,7 +43,8 @@
>    typedef ::itk::ImageIOBase::Pointer ImageIOBasePointer;
>  
>    /** Create the appropriate ImageIO depending on the particulars of the file. */
> -  static ImageIOBasePointer CreateImageIO(const char* path);
> +  static ImageIOBasePointer CreateImageIOReader(const char* path);
> +  static ImageIOBasePointer CreateImageIOWriter(const char* path);
>  
>  protected:
>    ImageIOFactory();
> 
> 
> ------------------------------------------------------------------------
> 
> --- itkImageIOFactory.cxx.old	Tue Jun 18 13:36:27 2002
> +++ itkImageIOFactory.cxx	Tue Jun 18 13:36:27 2002
> @@ -19,11 +19,10 @@
>  
>  namespace itk
>  {
> -  
>  
> -  
> +
>  ImageIOBase::Pointer 
> -ImageIOFactory::CreateImageIO(const char* path)
> +ImageIOFactory::CreateImageIOReader(const char* path)
>  {
>    std::list<ImageIOBase::Pointer> possibleImageIO;
>    std::list<LightObject::Pointer> allobjects = 
> @@ -50,6 +49,38 @@
>        {
>        return *k;
>        }
> +    }
> +  return 0;
> +}
> +
> +ImageIOBase::Pointer 
> +ImageIOFactory::CreateImageIOWriter(const char* path)
> +{
> +  std::list<ImageIOBase::Pointer> possibleImageIO;
> +  std::list<LightObject::Pointer> allobjects = 
> +                  ObjectFactoryBase::CreateAllInstance("itkImageIOBase");
> +  for(std::list<LightObject::Pointer>::iterator i = allobjects.begin();
> +      i != allobjects.end(); ++i)
> +    {
> +    ImageIOBase* io = dynamic_cast<ImageIOBase*>(i->GetPointer());
> +    if(io)
> +      {
> +      possibleImageIO.push_back(io);
> +      }
> +    else
> +      {
> +      std::cerr << "Error ImageIO factory did not return an ImageIOBase: "
> +                << (*i)->GetNameOfClass() 
> +                << std::endl;
> +      }
> +    }
> +  for(std::list<ImageIOBase::Pointer>::iterator k = possibleImageIO.begin();
> +      k != possibleImageIO.end(); ++k)
> +    { 
> +    if((*k)->CanWriteFile(path))
> +      {
> +      return *k;
> +      }
>      }
>    return 0;
>  }
> 
> 
> ------------------------------------------------------------------------
> 
> --- itkImageFileWriter.txx.old	Tue Jun 18 13:36:27 2002
> +++ itkImageFileWriter.txx	Tue Jun 18 13:36:27 2002
> @@ -101,7 +101,7 @@
>  
>    if ( m_ImageIO == 0 ) //try creating via factory
>      {
> -    m_ImageIO = ImageIOFactory::CreateImageIO(m_FileName.c_str());
> +    m_ImageIO = ImageIOFactory::CreateImageIOWriter(m_FileName.c_str());
>      }
>  
>    if ( m_ImageIO == 0 )
> 
> 
> ------------------------------------------------------------------------
> 
> --- itkImageFileReader.txx.old	Tue Jun 18 13:36:27 2002
> +++ itkImageFileReader.txx	Tue Jun 18 13:36:27 2002
> @@ -82,7 +82,7 @@
>    if ( m_ImageIO == 0 ) //try creating via factory
>      {
>      m_UserSpecified = false;
> -    m_ImageIO = ImageIOFactory::CreateImageIO(m_FileName.c_str());
> +    m_ImageIO = ImageIOFactory::CreateImageIOReader(m_FileName.c_str());
>      }
>    else
>      {
> 
> CMakeLists.txt
> 
> Content-Type:
> 
> text/plain
> Content-Encoding:
> 
> 7bit
> 
> 
> ------------------------------------------------------------------------
> FileWriteTest.cxx
> 
> Content-Type:
> 
> text/plain
> Content-Encoding:
> 
> 7bit
> 
> 
> ------------------------------------------------------------------------
> itkPNGImageIO.h.patch
> 
> Content-Type:
> 
> text/plain
> Content-Encoding:
> 
> 7bit
> 
> 
> ------------------------------------------------------------------------
> itkPNGImageIO.cxx.patch
> 
> Content-Type:
> 
> text/plain
> Content-Encoding:
> 
> 7bit
> 
> 
> ------------------------------------------------------------------------
> itkImageIOFactory.h.patch
> 
> Content-Type:
> 
> text/plain
> Content-Encoding:
> 
> 7bit
> 
> 
> ------------------------------------------------------------------------
> itkImageIOFactory.cxx.patch
> 
> Content-Type:
> 
> text/plain
> Content-Encoding:
> 
> 7bit
> 
> 
> ------------------------------------------------------------------------
> itkImageFileWriter.txx.patch
> 
> Content-Type:
> 
> text/plain
> Content-Encoding:
> 
> 7bit
> 
> 
> ------------------------------------------------------------------------
> itkImageFileReader.txx.patch
> 
> Content-Type:
> 
> text/plain
> Content-Encoding:
> 
> 7bit
> 
>