1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 #define OSG_COMPILE_IMAGEFILEHANDLER
44 #include "OSGConfig.h"
47 #include "OSGBaseTypes.h"
48 #include "OSGPathHandler.h"
49 #include "OSGBaseFunctions.h"
50 #include "OSGFileSystem.h"
52 #include "OSGImageFileHandler.h"
53 #include "OSGBoostPathAttachment.h"
55 #include "OSGSingletonHolder.ins"
59 /*! \class ImageFileHandlerBase
61 Singelton Object/Class which holds all known ImageFileTypes.
62 The class is used to write/read Image objects to/from
63 files and to store/restore image data to/from memory blocks.
64 Utilizes the local pathHandler for file path handler and
65 construction. The PathHandler can be set from the application.
67 See \ref PageSystemImage for details.
71 /*****************************
73 *****************************/
75 OSG_SINGLETON_INST(ImageFileHandlerBase
, addPostFactoryExitFunction
)
77 template class SingletonHolder
<ImageFileHandlerBase
>;
79 /*****************************
81 *****************************/
83 const std::string
ImageFileHandlerBase::_fileNameKey ("fileName" );
84 const std::string
ImageFileHandlerBase::_fullFilePathKey("fullFilePath");
86 /********************************
88 *******************************/
90 /*******************************
92 *******************************/
94 //-------------------------------------------------------------------------
95 /*! Method to find a ImageFileHandler for the given mimeType for
96 fileName suffix. Returns the ImageFileHandler object or Null.
99 ImageFileType
*ImageFileHandlerBase::getFileType(const Char8
*mimeType
,
100 const Char8
*fileName
,
104 ImageFileType
*type
= 0;
105 std::map
<std::string
,
106 ImageFileType
*>::iterator sI
;
107 const char separator
= '.';
110 if(mimeType
&& *mimeType
)
112 std::string mt
= mimeType
;
114 normalizeMimetype(mt
);
116 if(mt
.find('/') == std::string::npos
)
117 mt
.insert(0, "image/");
119 TypeMap::iterator tIt
= _mimeTypeMap
.find(mt
);
121 if(tIt
!= _mimeTypeMap
.end())
126 FWARNING (("Invalid mimeType %s in getFileType()\n", mimeType
));
130 if(!type
&& fileName
&& *fileName
)
136 l
= strlen(fileName
);
138 for(i
= l
- 1; i
>= 0; i
--)
140 if(fileName
[i
] == separator
)
146 suffix
.assign(&(fileName
[i
+ 1]));
148 normalizeSuffix(suffix
);
150 sI
= _suffixTypeMap
.find(suffix
);
152 type
= (sI
== _suffixTypeMap
.end()) ? 0 : sI
->second
;
159 // now validate the header of the file
161 bool implemented
= false;
166 !type
->validateHeader(fileName
, implemented
))
168 FWARNING (("Found wrong image header trying to "
169 "autodetect image type!\n"));
171 for(sI
= _suffixTypeMap
.begin(); sI
!= _suffixTypeMap
.end(); ++sI
)
175 if(type
!= NULL
&& type
->validateHeader(fileName
, implemented
))
179 FWARNING (("Autodetected '%s' image type!\n",
187 FWARNING (("Couldn't autodetect image type!\n"));
196 //-------------------------------------------------------------------------
197 /*! Returns the default OpenSG ImageFileType
200 ImageFileType
*ImageFileHandlerBase::getDefaultType(void)
202 std::string
dSuffix("opensg");
204 std::map
<std::string
,
205 ImageFileType
*>::iterator sI
= _suffixTypeMap
.find(dSuffix
);
208 ImageFileType
*type
= (sI
== _suffixTypeMap
.end()) ? 0 : sI
->second
;
212 FFATAL(("Can not find any default (suffix:%s) image handler\n",
220 //-------------------------------------------------------------------------
221 /*! Returns the list of supported image suffixes
224 Int32
ImageFileHandlerBase::getSuffixList(std::list
<const Char8
*> &suffixList
,
228 std::map
<std::string
,
229 ImageFileType
*>::iterator sI
;
233 for(sI
= _suffixTypeMap
.begin(); sI
!= _suffixTypeMap
.end(); ++sI
)
235 ImageFileType
*type
= sI
->second
;
237 if(type
->getFlags() & flags
)
239 suffixList
.push_back(sI
->first
.c_str());
247 const ImageFileHandlerBase::TypeMap
& ImageFileHandlerBase::getSuffixTypeMap() const
249 return _suffixTypeMap
;
252 const ImageFileHandlerBase::TypeMap
& ImageFileHandlerBase::getMimeTypeMap() const
257 //-------------------------------------------------------------------------
259 Tries to determine the mime type from the file name.
262 std::string
ImageFileHandlerBase::determineMimetypeFromName(
263 const std::string
&fileName
)
265 // Determine the suffix of the filename
266 std::string::size_type pos
= fileName
.rfind('.');
268 if(pos
== std::string::npos
)
269 return std::string();
271 std::string suffix
= fileName
.substr(pos
+ 1);
273 normalizeSuffix(suffix
);
275 // Try to find the suffix in the map of extensions
276 std::map
<std::string
,
277 ImageFileType
*>::iterator it
= _suffixTypeMap
.find(suffix
);
279 return it
!= _suffixTypeMap
.end() ?
280 std::string(it
->second
->getMimeType()) : std::string();
283 //-------------------------------------------------------------------------
285 tries to determine the mimetype of a stream.
288 std::string
ImageFileHandlerBase::determineMimetypeFromStream(std::istream
&is
)
290 std::string mimetype
;
291 TypeMap::iterator it
;
293 for(it
= _mimeTypeMap
.begin(); it
!= _mimeTypeMap
.end(); ++it
)
295 mimetype
= it
->second
->determineMimetypeFromStream(is
);
297 if(mimetype
.empty() == false)
304 //-------------------------------------------------------------------------
306 Tries to determine the mime type from the suffix.
308 std::string
ImageFileHandlerBase::determineMimetypeFromSuffix(
309 const std::string
&suffix
)
311 std::string s
= suffix
;
315 // Try to find the suffix in the map of extensions
316 std::map
<std::string
, ImageFileType
*>::iterator it
=
317 _suffixTypeMap
.find(s
);
319 return it
!= _suffixTypeMap
.end() ?
320 std::string(it
->second
->getMimeType()) : std::string();
323 //-------------------------------------------------------------------------
324 /*! Creates a new image and tries to read the raster data from
325 the given fileName. If the mimeType is not Null the method
326 will try to find the according ImageFileType. Otherwise it
327 will try to use the fileName suffix to determine the mimeType
331 ImageTransitPtr
ImageFileHandlerBase::read(const Char8
*fileName
,
332 const Char8
*mimeType
)
334 if(_pReadCallback
!= NULL
)
335 return _pReadCallback(fileName
, mimeType
);
337 ImageUnrecPtr image
= Image::create();
339 if(read(image
, fileName
, mimeType
) == false)
344 return ImageTransitPtr(image
);
347 //-------------------------------------------------------------------------
348 /*! Tries to read the raster data from
349 the given fileName into the given Image.
350 If the mimeType is not Null the method
351 will try to find the according ImageFileType. Otherwise it
352 will try to use the fileName suffix to determine the mimeType
355 bool ImageFileHandlerBase::read( Image
*pImage
,
356 const Char8
*fileName
,
357 const Char8
*mimeType
)
359 bool retCode
= false;
360 std::string fullFilePath
;
362 if(_pPathHandler
!= NULL
)
364 fullFilePath
= _pPathHandler
->findFile(fileName
);
368 fullFilePath
= fileName
;
371 if(fullFilePath
.empty())
373 SWARNING
<< "couldn't find image file " << fileName
<< std::endl
;
377 ImageFileType
*type
= getFileType(mimeType
, fullFilePath
.c_str(), true);
381 FDEBUG(("try to image read %s as %s\n",
382 fullFilePath
.c_str(),
383 type
->getMimeType()));
385 retCode
= type
->read(pImage
, fullFilePath
.c_str());
389 FDEBUG(("image: %dx%d\n",
391 pImage
->getHeight()));
393 pImage
->setAttachmentField(_fileNameKey
, fileName
);
394 pImage
->setAttachmentField(_fullFilePathKey
, fullFilePath
);
396 setBoostPath(pImage
, BoostPath(fullFilePath
));
398 // converting the path to a absolute path.
401 if(fullFilePath
[0] != '/' &&
402 fullFilePath
[0] != '\\' &&
403 fullFilePath
[1] != ':')
407 if(getPathHandler() != NULL
)
408 base
= getPathHandler()->getBaseFile();
410 if(base
.size() < 2 ||
411 (base
[0] != '/' && base
[0] != '\\' && base
[1] != ':'))
413 const Char8
*cdir
= Directory::getCurrent();
425 abspath
+= fullFilePath
;
429 abspath
= fullFilePath
;
432 pImage
->setName(abspath
);
436 SWARNING
<< "could not read " << fullFilePath
<< std::endl
;
441 SWARNING
<< "could not read " << fullFilePath
442 << "; unknown image format" << std::endl
;
448 void ImageFileHandlerBase::setReadCB(ReadCB pCB
)
450 _pReadCallback
= pCB
;
453 ImageFileHandlerBase::ReadCB
ImageFileHandlerBase::getReadCB(void)
455 return _pReadCallback
;
458 //-------------------------------------------------------------------------
459 /*! Tries to write the raster data (from the given Image) to
461 If the mimeType is not Null the method
462 will try to find the according ImageFileType. Otherwise it
463 will try to use the fileName suffix to determine the mimeType
466 bool ImageFileHandlerBase::write(Image
const *pImage
,
467 Char8
const *fileName
,
468 Char8
const *mimeType
)
470 bool retCode
= false;
472 const std::string
*fNAttachment
;
474 if(!fileName
&& (fNAttachment
= pImage
->findAttachmentField(_fileNameKey
)))
476 fileName
= fNAttachment
->c_str();
479 if((type
= getFileType(mimeType
, fileName
)))
481 SINFO
<< "try to write "
484 << type
->getMimeType()
487 retCode
= type
->write(pImage
, fileName
);
491 SWARNING
<< "can't write "
493 << "; unknown image format" << std::endl
;
499 //-------------------------------------------------------------------------
501 ImageTransitPtr
ImageFileHandlerBase::read( std::istream
&is
,
502 const std::string
&mimeType
)
504 ImageUnrecPtr image
= Image::create();
506 if (read(image
, is
, mimeType
) == false)
511 return ImageTransitPtr(image
);
514 //-------------------------------------------------------------------------
516 bool ImageFileHandlerBase::read( Image
*pImage
,
518 const std::string
&mimeType
)
520 ImageFileType
*type
= getFileType(mimeType
.c_str());
522 return type
== 0 ? false : type
->read(pImage
, is
, mimeType
);
525 //-------------------------------------------------------------------------
527 bool ImageFileHandlerBase::write(Image
const *pImage
,
529 std::string
const &mimeType
)
531 ImageFileType
*type
= getFileType(mimeType
.c_str());
533 return type
== 0 ? false : type
->write(pImage
, os
, mimeType
);
537 ImageFileHandlerBase::ImageBlockAccessorPtr
538 ImageFileHandlerBase::open(const Char8
*fileName
,
539 const Char8
*mimeType
)
541 ImageBlockAccessorPtr returnValue
;
542 std::string fullFilePath
;
544 if(_pPathHandler
!= NULL
)
546 fullFilePath
= _pPathHandler
->findFile(fileName
);
550 fullFilePath
= fileName
;
553 if(fullFilePath
.empty())
555 SWARNING
<< "couldn't find image file " << fileName
<< std::endl
;
559 ImageFileType
*type
= getFileType(mimeType
, fullFilePath
.c_str(), true);
563 FDEBUG(("try to image read %s as %s\n",
564 fullFilePath
.c_str(),
565 type
->getMimeType()));
567 returnValue
= type
->open(fullFilePath
.c_str());
571 SWARNING
<< "could not read " << fullFilePath
572 << "; unknown image format" << std::endl
;
579 //-------------------------------------------------------------------------
580 /*! Returns the path handler used
583 PathHandler
* ImageFileHandlerBase::getPathHandler(void)
585 return _pPathHandler
;
588 //-------------------------------------------------------------------------
589 /*! Method to set the path handler.
592 void ImageFileHandlerBase::setPathHandler(PathHandler
*pPathHandler
)
594 _pPathHandler
= pPathHandler
;
597 /*! Sets the option \a name to \a value for the ImageFileType that handles
598 files with the given \a suffix.
599 Returns \c true if the option was set successfully, \c false otherwise.
601 \param[in] suffix File extension to choose the image type
602 this option applies to.
603 \param[in] name Name of the option.
604 \param[in] value Value of the option.
605 \return Whether the value was set successfully.
608 ImageFileHandlerBase::setOption(
609 const std::string
&suffix
,
610 const std::string
&name
,
611 const std::string
&value
)
614 ImageFileType
*type
= getFileType(suffix
.c_str());
618 type
->setOption(name
, value
);
625 /*! Removes the option \a name from the ImageFileType that handles files
626 with the given \a suffix. If the option is not present \c false is
627 returned, \c true otherwise.
629 \param[in] suffix File extension to choose the image file type
630 this option applies to.
631 \param[in] name Name of the option.
632 \return Whether the option was successfully removed.
635 ImageFileHandlerBase::unsetOption(
636 const std::string
&suffix
,
637 const std::string
&name
)
640 ImageFileType
*type
= getFileType(suffix
.c_str());
644 retVal
= type
->unsetOption(name
);
650 /*! Retrieves the option \a name from the ImageFileType that handles files
651 with the given \a suffix and stores its value in \a value.
652 Returns \c true if successful, \c false otherwise in which case \a value has
655 \param[in] suffix File extension to choose the image type
656 this option applies to.
657 \param[in] name Name of the option.
658 \param[out] value Value the option.
659 \return Whether the option is present for the given ImageFileType.
662 ImageFileHandlerBase::getOption(
663 const std::string
&suffix
,
664 const std::string
&name
,
668 ImageFileType
*type
= getFileType(suffix
.c_str());
672 retVal
= type
->getOption(name
, value
);
678 //-------------------------------------------------------------------------
679 /*! Tries to restore the raster data from
680 the given memblock into the given Image.
681 If the mimeType is not Null the method
682 will try to find the according ImageFileType. Otherwise it
683 will try to use the fileName suffix to determine the mimeType
686 UInt64
ImageFileHandlerBase::restore( Image
*pImage
,
687 const UChar8
*buffer
,
690 return ImageFileType::restore(pImage
, buffer
, memSize
);
693 //-------------------------------------------------------------------------
694 /*! Tries to store the raster data (from the given Image) to
696 If the mimeType is not Null the method
697 will try to find the according ImageFileType. Otherwise it
698 will try to use the fileName suffix to determine the mimeType
701 UInt64
ImageFileHandlerBase::store(Image
const *pImage
,
702 Char8
const *mimeType
,
708 type
= mimeType
? getFileType(mimeType
) : getDefaultType();
710 return type
->store(pImage
, buffer
, memSize
);
713 //-------------------------------------------------------------------------
714 /*! Tries to store the raster data (from the given Image) to
715 a new memBlock. The method will automatically allocate and return a
716 sufficient amount of memory with new. The application has
717 to free the memory with 'delete [] mem'
718 If the mimeType is not Null the method
719 will try to find the according ImageFileType. Otherwise it
720 will try to use the fileName suffix to determine the mimeType
723 UChar8
*ImageFileHandlerBase::store(Image
const *pImage
,
725 Char8
const *mimeType
)
727 ImageFileType
*type
= 0;
730 type
= mimeType
? getFileType(mimeType
) : getDefaultType();
731 memSize
= type
->maxBufferSize(pImage
);
735 mem
= new UChar8
[size_t(memSize
)];
737 memSize
= type
->store(pImage
, mem
, Int32(memSize
));
741 FFATAL(("Can not store the image as %s\n", type
->getMimeType()));
747 //-------------------------------------------------------------------------
748 /*! The dump method just writes some object debugging info to the LOG stream
751 void ImageFileHandlerBase::dump(void)
753 std::map
<std::string
, ImageFileType
*>::iterator sI
;
755 for(sI
= _suffixTypeMap
.begin(); sI
!= _suffixTypeMap
.end(); sI
++)
757 FLOG (( "Image suffix: %s, mimeType: %s\n",
758 sI
->first
.c_str(), sI
->second
->getMimeType() ));
762 //-------------------------------------------------------------------------
763 /*! Internal Method to add a new ImageFileType
766 bool ImageFileHandlerBase::addImageFileType(ImageFileType
&fileType
)
768 bool retCode
= false;
769 std::list
<std::string
>::const_iterator sI
;
770 std::map
<std::string
,
771 ImageFileType
*>::iterator smI
;
774 for( sI
= fileType
.getSuffixList().begin();
775 sI
!= fileType
.getSuffixList().end();
778 suffix
.assign(sI
->c_str());
780 normalizeSuffix(suffix
);
782 smI
= _suffixTypeMap
.find(suffix
);
784 if(smI
!= _suffixTypeMap
.end())
786 SWARNING
<< "Can't add an image file type with suffix "
787 << suffix
<< " a second time" << std::endl
;
791 _suffixTypeMap
[suffix
] = &fileType
;
797 std::string mimetype
= fileType
.getMimeType();
799 normalizeMimetype(mimetype
);
801 TypeMap::iterator tIt
= _mimeTypeMap
.find(mimetype
);
803 if(tIt
!= _mimeTypeMap
.end())
805 SWARNING
<< "Can't add an image file type with mimetype "
806 << mimetype
<< " a second time" << std::endl
;
810 _mimeTypeMap
[mimetype
] = &fileType
;
816 //----------------------------------------------------------------------
818 Normalizes a mime type, i.e. removes parameters and whitespaces
819 and transforms it to lowercase
822 void ImageFileHandlerBase::normalizeMimetype(std::string
&mimetype
)
824 // Remove any parameters
825 std::string::size_type endpos
= mimetype
.find(';');
833 if (endpos
!= std::string::npos
)
836 // Remove trailing whitespace
838 endpos
= mimetype
.find_last_not_of(" \t\r\n", endpos
);
840 if (endpos
== std::string::npos
)
846 mimetype
.erase(endpos
+ 1);
848 // Remove leading whitespace
849 std::string::size_type startpos
= mimetype
.find_first_not_of(" \t\r\n");
851 if(startpos
== std::string::npos
)
857 mimetype
.erase(0, startpos
);
859 // Transform to lower case
860 std::transform(mimetype
.begin(),
866 //-------------------------------------------------------------------------
868 Normalizes a suffix, i.e. removes whitespaces and transforms it to lowercase
870 void ImageFileHandlerBase::normalizeSuffix(std::string
&suffix
)
872 // Remove trailing whitespace
873 std::string::size_type endpos
= suffix
.find_last_not_of(" \t\r\n");
875 if (endpos
== std::string::npos
)
881 suffix
.erase(endpos
+ 1);
883 // Remove leading whitespace
884 std::string::size_type startpos
= suffix
.find_first_not_of(" \t\r\n");
886 if (startpos
== std::string::npos
)
892 suffix
.erase(0, startpos
);
894 // Transform to lower case
895 std::transform(suffix
.begin(), suffix
.end(), suffix
.begin(), ::tolower
);
898 //-------------------------------------------------------------------------
899 /*! Default Constructor
902 ImageFileHandlerBase::ImageFileHandlerBase(void) :
903 _pReadCallback(NULL
),
904 _pPathHandler (NULL
),
910 //-------------------------------------------------------------------------
914 ImageFileHandlerBase::~ImageFileHandlerBase(void)