From 77dba7664c2680a1beb4102c76a14c32ffa7ba66 Mon Sep 17 00:00:00 2001 From: kgv Date: Sat, 9 Mar 2019 05:07:01 +0300 Subject: [PATCH] 0030549: Coding - split Image_AlienPixMap into several classes Image_AlienPixMap has been split into: - Image_AlienPixMapI defining a general interface for reading/writing images from/to external files. - Image_FreeImage implementing interface using FreeImage library. - Image_WinCodec implementing interface using WinCodec library. - Image_AlienPixMap redirecting to either Image_FreeImage or Image_WinCodec. New static method Image_AlienPixMap::SetDefaultFactory() allows configuring an external image library implementing Image_AlienPixMapI interface to be used by default OCCT image processing routines (texturing, image dumps, etc.). --- src/Draw/Draw_Window.cxx | 30 +- src/Image/FILES | 6 + src/Image/Image_AlienPixMap.cxx | 1092 +++--------------------------- src/Image/Image_AlienPixMap.hxx | 88 ++- src/Image/Image_AlienPixMapI.cxx | 151 +++++ src/Image/Image_AlienPixMapI.hxx | 98 +++ src/Image/Image_FreeImage.cxx | 655 ++++++++++++++++++ src/Image/Image_FreeImage.hxx | 107 +++ src/Image/Image_PixMap.hxx | 2 +- src/Image/Image_WinCodec.cxx | 451 ++++++++++++ src/Image/Image_WinCodec.hxx | 87 +++ 11 files changed, 1700 insertions(+), 1067 deletions(-) create mode 100644 src/Image/Image_AlienPixMapI.cxx create mode 100644 src/Image/Image_AlienPixMapI.hxx create mode 100644 src/Image/Image_FreeImage.cxx create mode 100644 src/Image/Image_FreeImage.hxx create mode 100644 src/Image/Image_WinCodec.cxx create mode 100644 src/Image/Image_WinCodec.hxx diff --git a/src/Draw/Draw_Window.cxx b/src/Draw/Draw_Window.cxx index 41f779650f..e5e7d8da39 100644 --- a/src/Draw/Draw_Window.cxx +++ b/src/Draw/Draw_Window.cxx @@ -1804,26 +1804,40 @@ static Standard_Boolean SaveBitmap (HBITMAP theHBitmap, { return Standard_False; } - anImage.SetTopDown (false); // Setup image data BITMAPINFOHEADER aBitmapInfo; memset (&aBitmapInfo, 0, sizeof(BITMAPINFOHEADER)); aBitmapInfo.biSize = sizeof(BITMAPINFOHEADER); aBitmapInfo.biWidth = aBitmap.bmWidth; - aBitmapInfo.biHeight = aBitmap.bmHeight; // positive means bottom-up! + aBitmapInfo.biHeight = anImage.IsTopDown() ? -aBitmap.bmHeight : aBitmap.bmHeight; aBitmapInfo.biPlanes = 1; aBitmapInfo.biBitCount = 24; aBitmapInfo.biCompression = BI_RGB; // Copy the pixels HDC aDC = GetDC (NULL); - Standard_Boolean isSuccess = GetDIBits (aDC, theHBitmap, - 0, // first scan line to set - aBitmap.bmHeight, // number of scan lines to copy - anImage.ChangeData(), // array for bitmap bits - (LPBITMAPINFO )&aBitmapInfo, // bitmap data info - DIB_RGB_COLORS) != 0; + Standard_Boolean isSuccess = Standard_True; + if (anImage.SizeRowBytes() != aSizeRowBytes) + { + for (Standard_Size aRowIter = 0; aRowIter < anImage.SizeY(); ++aRowIter) + { + const Standard_Size aRow = anImage.SizeY() - aRowIter - 1; + isSuccess = isSuccess && GetDIBits (aDC, theHBitmap, + (UINT )aRow, 1, + anImage.ChangeRow (aRowIter), + (LPBITMAPINFO )&aBitmapInfo, DIB_RGB_COLORS) != 0; + } + } + else + { + isSuccess = GetDIBits (aDC, theHBitmap, + 0, // first scan line to set + aBitmap.bmHeight, // number of scan lines to copy + anImage.ChangeData(), // array for bitmap bits + (LPBITMAPINFO )&aBitmapInfo, // bitmap data info + DIB_RGB_COLORS) != 0; + } ReleaseDC (NULL, aDC); return isSuccess && anImage.Save (theFileName); } diff --git a/src/Image/FILES b/src/Image/FILES index 40118d5bca..dc19f8162d 100755 --- a/src/Image/FILES +++ b/src/Image/FILES @@ -1,12 +1,18 @@ Image_AlienPixMap.cxx Image_AlienPixMap.hxx +Image_AlienPixMapI.cxx +Image_AlienPixMapI.hxx Image_Color.hxx Image_Diff.cxx Image_Diff.hxx Image_Format.hxx +Image_FreeImage.cxx +Image_FreeImage.hxx Image_PixMap.cxx Image_PixMap.hxx Image_PixMapData.hxx Image_PixMapTypedData.hxx Image_VideoRecorder.cxx Image_VideoRecorder.hxx +Image_WinCodec.cxx +Image_WinCodec.hxx \ No newline at end of file diff --git a/src/Image/Image_AlienPixMap.cxx b/src/Image/Image_AlienPixMap.cxx index ba166a5fc6..eee10a63f5 100644 --- a/src/Image/Image_AlienPixMap.cxx +++ b/src/Image/Image_AlienPixMap.cxx @@ -13,463 +13,99 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. -#if !defined(HAVE_FREEIMAGE) && defined(_WIN32) - #define HAVE_WINCODEC -#endif - -#ifdef HAVE_FREEIMAGE - #include +#include - #ifdef _MSC_VER - #pragma comment( lib, "FreeImage.lib" ) - #endif -#elif defined(HAVE_WINCODEC) - //#include - #include - #undef min - #undef max -#endif +#include +#include -#include -#include #include #include -#include -#include #include #include -#include -#include -#include IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap,Image_PixMap) namespace { -#ifdef HAVE_FREEIMAGE - static Image_Format convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI, - FREE_IMAGE_COLOR_TYPE theColorTypeFI, - unsigned theBitsPerPixel) + //! Global instance of image factory. + static Handle(Image_AlienPixMapI)& getFactory() { - switch (theFormatFI) - { - case FIT_RGBF: return Image_Format_RGBF; - case FIT_RGBAF: return Image_Format_RGBAF; - case FIT_FLOAT: return Image_Format_GrayF; - case FIT_BITMAP: - { - switch (theColorTypeFI) - { - case FIC_MINISBLACK: - { - return Image_Format_Gray; - } - case FIC_RGB: - { - if (Image_PixMap::IsBigEndianHost()) - { - return (theBitsPerPixel == 32) ? Image_Format_RGB32 : Image_Format_RGB; - } - else - { - return (theBitsPerPixel == 32) ? Image_Format_BGR32 : Image_Format_BGR; - } - } - case FIC_RGBALPHA: - { - return Image_PixMap::IsBigEndianHost() ? Image_Format_RGBA : Image_Format_BGRA; - } - default: - return Image_Format_UNKNOWN; - } - } - default: - return Image_Format_UNKNOWN; - } - } - - static FREE_IMAGE_TYPE convertToFreeFormat (Image_Format theFormat) - { - switch (theFormat) - { - case Image_Format_GrayF: - case Image_Format_AlphaF: - return FIT_FLOAT; - case Image_Format_RGBAF: - return FIT_RGBAF; - case Image_Format_RGBF: - return FIT_RGBF; - case Image_Format_RGBA: - case Image_Format_BGRA: - case Image_Format_RGB32: - case Image_Format_BGR32: - case Image_Format_RGB: - case Image_Format_BGR: - case Image_Format_Gray: - case Image_Format_Alpha: - return FIT_BITMAP; - default: - return FIT_UNKNOWN; - } - } - - //! Wrapper for accessing C++ stream from FreeImage. - class Image_FreeImageStream - { - public: - //! Construct wrapper over input stream. - Image_FreeImageStream (std::istream& theStream) - : myIStream (&theStream), myOStream (NULL), myInitPos (theStream.tellg()) {} - - //! Get io object. - FreeImageIO GetFiIO() const - { - FreeImageIO anIo; - memset (&anIo, 0, sizeof(anIo)); - if (myIStream != NULL) - { - anIo.read_proc = readProc; - anIo.seek_proc = seekProc; - anIo.tell_proc = tellProc; - } - if (myOStream != NULL) - { - anIo.write_proc = writeProc; - } - return anIo; - } - public: - //! Simulate fread(). - static unsigned int DLL_CALLCONV readProc (void* theBuffer, unsigned int theSize, unsigned int theCount, fi_handle theHandle) - { - Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle; - if (aThis->myIStream == NULL) - { - return 0; - } - - if (!aThis->myIStream->read ((char* )theBuffer, std::streamsize(theSize) * std::streamsize(theCount))) - { - //aThis->myIStream->clear(); - } - const std::streamsize aNbRead = aThis->myIStream->gcount(); - return (unsigned int )(aNbRead / theSize); - } - - //! Simulate fwrite(). - static unsigned int DLL_CALLCONV writeProc (void* theBuffer, unsigned int theSize, unsigned int theCount, fi_handle theHandle) - { - Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle; - if (aThis->myOStream != NULL - && aThis->myOStream->write ((const char* )theBuffer, std::streamsize(theSize) * std::streamsize(theCount))) - { - return theCount; - } - return 0; - } - - //! Simulate fseek(). - static int DLL_CALLCONV seekProc (fi_handle theHandle, long theOffset, int theOrigin) - { - Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle; - if (aThis->myIStream == NULL) - { - return -1; - } - - bool isSeekDone = false; - switch (theOrigin) - { - case SEEK_SET: - if (aThis->myIStream->seekg ((std::streamoff )aThis->myInitPos + theOffset, std::ios::beg)) - { - isSeekDone = true; - } - break; - case SEEK_CUR: - if (aThis->myIStream->seekg (theOffset, std::ios::cur)) - { - isSeekDone = true; - } - break; - case SEEK_END: - if (aThis->myIStream->seekg (theOffset, std::ios::end)) - { - isSeekDone = true; - } - break; - } - return isSeekDone ? 0 : -1; - } - - //! Simulate ftell(). - static long DLL_CALLCONV tellProc (fi_handle theHandle) - { - Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle; - const long aPos = aThis->myIStream != NULL ? (long )(aThis->myIStream->tellg() - aThis->myInitPos) : 0; - return aPos; - } - private: - std::istream* myIStream; - std::ostream* myOStream; - std::streampos myInitPos; - }; - -#elif defined(HAVE_WINCODEC) - - //! Return a zero GUID - static GUID getNullGuid() - { - GUID aGuid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }; - return aGuid; - } - - //! Sentry over IUnknown pointer. - template class Image_ComPtr - { - public: - //! Empty constructor. - Image_ComPtr() - : myPtr (NULL) {} - - //! Destructor. - ~Image_ComPtr() - { - Nullify(); - } - - //! Return TRUE if pointer is NULL. - bool IsNull() const { return myPtr == NULL; } - - //! Release the pointer. - void Nullify() - { - if (myPtr != NULL) - { - myPtr->Release(); - myPtr = NULL; - } - } - - //! Return pointer for initialization. - T*& ChangePtr() - { - Standard_ASSERT_RAISE (myPtr == NULL, "Pointer cannot be initialized twice!"); - return myPtr; - } - - //! Return pointer. - T* get() { return myPtr; } - - //! Return pointer. - T* operator->() { return get(); } - - //! Cast handle to contained type - T& operator*() { return *get(); } - - private: - T* myPtr; - }; - - //! Convert WIC GUID to Image_Format. - static Image_Format convertFromWicFormat (const WICPixelFormatGUID& theFormat) - { - if (theFormat == GUID_WICPixelFormat32bppBGRA) - { - return Image_Format_BGRA; - } - else if (theFormat == GUID_WICPixelFormat32bppBGR) - { - return Image_Format_BGR32; - } - else if (theFormat == GUID_WICPixelFormat24bppRGB) - { - return Image_Format_RGB; - } - else if (theFormat == GUID_WICPixelFormat24bppBGR) - { - return Image_Format_BGR; - } - else if (theFormat == GUID_WICPixelFormat8bppGray) - { - return Image_Format_Gray; - } - return Image_Format_UNKNOWN; + static Handle(Image_AlienPixMapI) THE_IMAGE_FACTORY = + #if defined(HAVE_FREEIMAGE) + new Image_FreeImage(); + #elif defined(HAVE_WINCODEC) + new Image_WinCodec(); + #else + Handle(Image_AlienPixMapI)(); + #endif + return THE_IMAGE_FACTORY; } +} - //! Convert Image_Format to WIC GUID. - static WICPixelFormatGUID convertToWicFormat (Image_Format theFormat) +// ======================================================================= +// function : CreateDefault +// purpose : +// ======================================================================= +Handle(Image_AlienPixMapI) Image_AlienPixMap::CreateDefault() +{ + if (!getFactory().IsNull()) { - switch (theFormat) - { - case Image_Format_BGRA: return GUID_WICPixelFormat32bppBGRA; - case Image_Format_BGR32: return GUID_WICPixelFormat32bppBGR; - case Image_Format_RGB: return GUID_WICPixelFormat24bppRGB; - case Image_Format_BGR: return GUID_WICPixelFormat24bppBGR; - case Image_Format_Gray: return GUID_WICPixelFormat8bppGray; - case Image_Format_Alpha: return GUID_WICPixelFormat8bppGray; // GUID_WICPixelFormat8bppAlpha - case Image_Format_GrayF: // GUID_WICPixelFormat32bppGrayFloat - case Image_Format_AlphaF: - case Image_Format_RGBAF: // GUID_WICPixelFormat128bppRGBAFloat - case Image_Format_RGBF: // GUID_WICPixelFormat96bppRGBFloat - case Image_Format_RGBA: // GUID_WICPixelFormat32bppRGBA - case Image_Format_RGB32: // GUID_WICPixelFormat32bppRGB - default: - return getNullGuid(); - } + return getFactory()->createDefault(); } - -#endif + return Handle(Image_AlienPixMapI)(); } // ======================================================================= -// function : Image_AlienPixMap +// function : SetDefaultFactory // purpose : // ======================================================================= -Image_AlienPixMap::Image_AlienPixMap() -: myLibImage (NULL) +void Image_AlienPixMap::SetDefaultFactory (const Handle(Image_AlienPixMapI)& theLibrary) { - SetTopDown (false); + getFactory() = theLibrary; } // ======================================================================= -// function : ~Image_AlienPixMap +// function : Image_AlienPixMap // purpose : // ======================================================================= -Image_AlienPixMap::~Image_AlienPixMap() +Image_AlienPixMap::Image_AlienPixMap() { - Clear(); + myLibImage = CreateDefault(); } // ======================================================================= -// function : InitWrapper +// function : ~Image_AlienPixMap // purpose : // ======================================================================= -bool Image_AlienPixMap::InitWrapper (Image_Format, - Standard_Byte*, - const Standard_Size, - const Standard_Size, - const Standard_Size) +Image_AlienPixMap::~Image_AlienPixMap() { Clear(); - return false; } // ======================================================================= // function : InitTrash // purpose : // ======================================================================= -#ifdef HAVE_FREEIMAGE -bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat, - const Standard_Size theSizeX, - const Standard_Size theSizeY, - const Standard_Size /*theSizeRowBytes*/) -{ - Clear(); - FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat); - int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8; - if (aFormatFI == FIT_UNKNOWN) - { - aFormatFI = FIT_BITMAP; - aBitsPerPixel = 24; - } - - FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel); - Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage), - FreeImage_GetColorType(anImage), - FreeImage_GetBPP (anImage)); - if (thePixelFormat == Image_Format_BGR32 - || thePixelFormat == Image_Format_RGB32) - { - //FreeImage_SetTransparent (anImage, FALSE); - aFormat = (aFormat == Image_Format_BGRA) ? Image_Format_BGR32 : Image_Format_RGB32; - } - - Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage), - FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); - SetTopDown (false); - - // assign image after wrapper initialization (virtual Clear() called inside) - myLibImage = anImage; - return true; -} -#elif defined(HAVE_WINCODEC) bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat, const Standard_Size theSizeX, const Standard_Size theSizeY, const Standard_Size theSizeRowBytes) { Clear(); - Image_Format aFormat = thePixelFormat; - switch (aFormat) + if (myLibImage.IsNull()) { - case Image_Format_RGB: - aFormat = Image_Format_BGR; - break; - case Image_Format_RGB32: - aFormat = Image_Format_BGR32; - break; - case Image_Format_RGBA: - aFormat = Image_Format_BGRA; - break; - default: - break; + return base_type::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes); } - - if (!Image_PixMap::InitTrash (aFormat, theSizeX, theSizeY, theSizeRowBytes)) + if (myLibImage->InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes)) { - return false; - } - SetTopDown (true); - return true; -} -#else -bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat, - const Standard_Size theSizeX, - const Standard_Size theSizeY, - const Standard_Size theSizeRowBytes) -{ - return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes); -} -#endif - -// ======================================================================= -// function : InitCopy -// purpose : -// ======================================================================= -bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy) -{ - if (&theCopy == this) - { - // self-copying disallowed - return false; - } - if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes())) - { - return false; - } - - if (myImgFormat == theCopy.Format()) - { - if (SizeRowBytes() == theCopy.SizeRowBytes() - && TopDownInc() == theCopy.TopDownInc()) - { - // copy with one call - memcpy (ChangeData(), theCopy.Data(), std::min (SizeBytes(), theCopy.SizeBytes())); - return true; - } - - // copy row-by-row - const Standard_Size aRowSizeBytes = std::min (SizeRowBytes(), theCopy.SizeRowBytes()); - for (Standard_Size aRow = 0; aRow < myData.SizeY; ++aRow) - { - memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes); - } + Handle(Image_AlienPixMapI) aLibImage = myLibImage; + myLibImage.Nullify(); // prevent clearing + initWrapper (aLibImage->Format(), aLibImage->ChangeData(), + aLibImage->SizeX(), aLibImage->SizeY(), aLibImage->SizeRowBytes()); + myLibImage = aLibImage; + base_type::SetTopDown (myLibImage->IsTopDown()); return true; } - - // pixel format conversion required - Clear(); return false; } @@ -480,13 +116,10 @@ bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy) void Image_AlienPixMap::Clear() { Image_PixMap::Clear(); -#ifdef HAVE_FREEIMAGE - if (myLibImage != NULL) + if (!myLibImage.IsNull()) { - FreeImage_Unload (myLibImage); - myLibImage = NULL; + myLibImage->Clear(); } -#endif } // ======================================================================= @@ -495,345 +128,53 @@ void Image_AlienPixMap::Clear() // ======================================================================= bool Image_AlienPixMap::IsTopDownDefault() { -#ifdef HAVE_FREEIMAGE - return false; -#elif defined(HAVE_WINCODEC) - return true; -#else - return false; -#endif + return getFactory().IsNull() + || getFactory()->IsTopDown(); } // ======================================================================= // function : Load // purpose : // ======================================================================= -#ifdef HAVE_FREEIMAGE bool Image_AlienPixMap::Load (const Standard_Byte* theData, Standard_Size theLength, const TCollection_AsciiString& theImagePath) { Clear(); - -#ifdef _WIN32 - const TCollection_ExtendedString aFileNameW (theImagePath); -#endif - FREE_IMAGE_FORMAT aFIF = FIF_UNKNOWN; - FIMEMORY* aFiMem = NULL; - if (theData != NULL) - { - aFiMem = FreeImage_OpenMemory ((BYTE* )theData, (DWORD )theLength); - aFIF = FreeImage_GetFileTypeFromMemory (aFiMem, 0); - } - else - { - #ifdef _WIN32 - aFIF = FreeImage_GetFileTypeU (aFileNameW.ToWideString(), 0); - #else - aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0); - #endif - } - if (aFIF == FIF_UNKNOWN) - { - // no signature? try to guess the file format from the file extension - aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString()); - } - if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF)) - { - ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported file format.", - Message_Fail); - if (aFiMem != NULL) - { - FreeImage_CloseMemory (aFiMem); - } - return false; - } - - int aLoadFlags = 0; - if (aFIF == FIF_GIF) - { - // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading - aLoadFlags = GIF_PLAYBACK; - } - else if (aFIF == FIF_ICO) - { - // convert to 32bpp and create an alpha channel from the AND-mask when loading - aLoadFlags = ICO_MAKEALPHA; - } - - FIBITMAP* anImage = NULL; - if (theData != NULL) - { - anImage = FreeImage_LoadFromMemory (aFIF, aFiMem, aLoadFlags); - FreeImage_CloseMemory (aFiMem); - aFiMem = NULL; - } - else - { - #ifdef _WIN32 - anImage = FreeImage_LoadU (aFIF, aFileNameW.ToWideString(), aLoadFlags); - #else - anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags); - #endif - } - if (anImage == NULL) - { - TCollection_AsciiString aMessage = "Error: image file '"; - aMessage.AssignCat (theImagePath); - aMessage.AssignCat ("' is missing or invalid."); - ::Message::DefaultMessenger()->Send (aMessage, Message_Fail); - return false; - } - - Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage), - FreeImage_GetColorType(anImage), - FreeImage_GetBPP (anImage)); - if (aFormat == Image_Format_UNKNOWN) - { - //anImage = FreeImage_ConvertTo24Bits (anImage); - ::Message::DefaultMessenger()->Send ( TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported pixel format.", - Message_Fail); - return false; - } - - Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage), - FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); - SetTopDown (false); - - // assign image after wrapper initialization (virtual Clear() called inside) - myLibImage = anImage; - return true; -} - -bool Image_AlienPixMap::Load (std::istream& theStream, - const TCollection_AsciiString& theFileName) -{ - Clear(); - - Image_FreeImageStream aStream (theStream); - FreeImageIO aFiIO = aStream.GetFiIO(); - - FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeFromHandle (&aFiIO, &aStream, 0); - if (aFIF == FIF_UNKNOWN) - { - // no signature? try to guess the file format from the file extension - aFIF = FreeImage_GetFIFFromFilename (theFileName.ToCString()); - } - if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF)) - { - ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported file format.", - Message_Fail); - return false; - } - - int aLoadFlags = 0; - if (aFIF == FIF_GIF) - { - // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading - aLoadFlags = GIF_PLAYBACK; - } - else if (aFIF == FIF_ICO) - { - // convert to 32bpp and create an alpha channel from the AND-mask when loading - aLoadFlags = ICO_MAKEALPHA; - } - - FIBITMAP* anImage = FreeImage_LoadFromHandle (aFIF, &aFiIO, &aStream, aLoadFlags); - if (anImage == NULL) - { - ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' is missing or invalid.", - Message_Fail); - return false; - } - - Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage), - FreeImage_GetColorType(anImage), - FreeImage_GetBPP (anImage)); - if (aFormat == Image_Format_UNKNOWN) - { - ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported pixel format.", - Message_Fail); - return false; - } - - Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage), - FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); - SetTopDown (false); - - // assign image after wrapper initialization (virtual Clear() called inside) - myLibImage = anImage; - return true; -} - -#elif defined(HAVE_WINCODEC) -bool Image_AlienPixMap::Load (const Standard_Byte* theData, - Standard_Size theLength, - const TCollection_AsciiString& theFileName) -{ - Clear(); - - Image_ComPtr aWicImgFactory; - CoInitializeEx (NULL, COINIT_MULTITHREADED); - if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail); - return false; - } - - Image_ComPtr aWicDecoder; - Image_ComPtr aWicStream; - if (theData != NULL) - { - if (aWicImgFactory->CreateStream (&aWicStream.ChangePtr()) != S_OK - || aWicStream->InitializeFromMemory ((BYTE* )theData, (DWORD )theLength) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Stream", Message_Fail); - return false; - } - if (aWicImgFactory->CreateDecoderFromStream (aWicStream.get(), NULL, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail); - return false; - } - } - else - { - const TCollection_ExtendedString aFileNameW (theFileName); - if (aWicImgFactory->CreateDecoderFromFilename (aFileNameW.ToWideString(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail); - return false; - } - } - - UINT aFrameCount = 0, aFrameSizeX = 0, aFrameSizeY = 0; - WICPixelFormatGUID aWicPixelFormat = getNullGuid(); - Image_ComPtr aWicFrameDecode; - if (aWicDecoder->GetFrameCount (&aFrameCount) != S_OK - || aFrameCount < 1 - || aWicDecoder->GetFrame (0, &aWicFrameDecode.ChangePtr()) != S_OK - || aWicFrameDecode->GetSize (&aFrameSizeX, &aFrameSizeY) != S_OK - || aWicFrameDecode->GetPixelFormat (&aWicPixelFormat)) - { - Message::DefaultMessenger()->Send ("Error: cannot get WIC Image Frame", Message_Fail); - return false; - } - - Image_ComPtr aWicConvertedFrame; - Image_Format aPixelFormat = convertFromWicFormat (aWicPixelFormat); - if (aPixelFormat == Image_Format_UNKNOWN) - { - aPixelFormat = Image_Format_RGB; - if (aWicImgFactory->CreateFormatConverter (&aWicConvertedFrame.ChangePtr()) != S_OK - || aWicConvertedFrame->Initialize (aWicFrameDecode.get(), convertToWicFormat (aPixelFormat), WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot convert WIC Image Frame to RGB format", Message_Fail); - return false; - } - aWicFrameDecode.Nullify(); - } - - if (!Image_PixMap::InitTrash (aPixelFormat, aFrameSizeX, aFrameSizeY)) - { - Message::DefaultMessenger()->Send ("Error: cannot initialize memory for image", Message_Fail); - return false; - } - - IWICBitmapSource* aWicSrc = aWicFrameDecode.get(); - if(!aWicConvertedFrame.IsNull()) - { - aWicSrc = aWicConvertedFrame.get(); - } - if (aWicSrc->CopyPixels (NULL, (UINT )SizeRowBytes(), (UINT )SizeBytes(), ChangeData()) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot copy pixels from WIC Image", Message_Fail); - return false; - } - SetTopDown (true); - return true; -} -bool Image_AlienPixMap::Load (std::istream& theStream, - const TCollection_AsciiString& theFilePath) -{ - Clear(); - - // fallback copying stream data into transient buffer - const std::streamoff aStart = theStream.tellg(); - theStream.seekg (0, std::ios::end); - const Standard_Integer aLen = Standard_Integer(theStream.tellg() - aStart); - theStream.seekg (aStart); - if (aLen <= 0) - { - Message::DefaultMessenger()->Send ("Error: empty stream", Message_Fail); - return false; - } - - NCollection_Array1 aBuff (1, aLen); - if (!theStream.read ((char* )&aBuff.ChangeFirst(), aBuff.Size())) - { - Message::DefaultMessenger()->Send ("Error: unable to read stream", Message_Fail); - return false; + if (!myLibImage.IsNull() + && myLibImage->Load (theData, theLength, theImagePath)) + { + Handle(Image_AlienPixMapI) aLibImage = myLibImage; + myLibImage.Nullify(); // prevent clearing + initWrapper (aLibImage->Format(), aLibImage->ChangeData(), + aLibImage->SizeX(), aLibImage->SizeY(), aLibImage->SizeRowBytes()); + myLibImage = aLibImage; + base_type::SetTopDown (myLibImage->IsTopDown()); + return true; } - - return Load (&aBuff.ChangeFirst(), aBuff.Size(), theFilePath); -} -#else -bool Image_AlienPixMap::Load (std::istream& , - const TCollection_AsciiString& ) -{ - Clear(); - Message::DefaultMessenger()->Send ("Error: no image library available", Message_Fail); - return false; -} -bool Image_AlienPixMap::Load (const Standard_Byte* , - Standard_Size , - const TCollection_AsciiString& ) -{ - Clear(); - Message::DefaultMessenger()->Send ("Error: no image library available", Message_Fail); return false; } -#endif // ======================================================================= -// function : savePPM +// function : Load // purpose : // ======================================================================= -bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const +bool Image_AlienPixMap::Load (std::istream& theStream, + const TCollection_AsciiString& theFileName) { - if (IsEmpty()) - { - return false; - } - - // Open file - FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb"); - if (aFile == NULL) - { - return false; - } - - // Write header - fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY()); - fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n"); - - // Write pixel data - Standard_Byte aByte; - for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) - { - for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol) - { - // extremely SLOW but universal (implemented for all supported pixel formats) - const Quantity_ColorRGBA aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow); - aByte = Standard_Byte(aColor.GetRGB().Red() * 255.0); fwrite (&aByte, 1, 1, aFile); - aByte = Standard_Byte(aColor.GetRGB().Green() * 255.0); fwrite (&aByte, 1, 1, aFile); - aByte = Standard_Byte(aColor.GetRGB().Blue() * 255.0); fwrite (&aByte, 1, 1, aFile); - } + Clear(); + if (!myLibImage.IsNull() + && myLibImage->Load (theStream, theFileName)) + { + Handle(Image_AlienPixMapI) aLibImage = myLibImage; + myLibImage.Nullify(); // prevent clearing + initWrapper (aLibImage->Format(), aLibImage->ChangeData(), + aLibImage->SizeX(), aLibImage->SizeY(), aLibImage->SizeRowBytes()); + myLibImage = aLibImage; + base_type::SetTopDown (myLibImage->IsTopDown()); + return true; } - - // Close file - fclose (aFile); - return true; + return false; } // ======================================================================= @@ -842,302 +183,27 @@ bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) con // ======================================================================= bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName) { -#ifdef HAVE_FREEIMAGE - if (myLibImage == NULL) - { - return false; - } - -#ifdef _WIN32 - const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True); - FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU (aFileNameW.ToWideString()); -#else - FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString()); -#endif - if (anImageFormat == FIF_UNKNOWN) - { -#ifdef OCCT_DEBUG - std::cerr << "Image_PixMap, image format doesn't supported!\n"; -#endif - return false; - } - - if (IsTopDown()) - { - FreeImage_FlipVertical (myLibImage); - SetTopDown (false); - } - - // FreeImage doesn't provide flexible format conversion API - // so we should perform multiple conversions in some cases! - FIBITMAP* anImageToDump = myLibImage; - switch (anImageFormat) - { - case FIF_PNG: - case FIF_BMP: - { - if (Format() == Image_Format_BGR32 - || Format() == Image_Format_RGB32) - { - // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF - for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) - { - for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol) - { - myData.ChangeValue (aRow, aCol)[3] = 0xFF; - } - } - } - else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) - { - anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); - } - break; - } - case FIF_GIF: - { - FIBITMAP* aTmpBitmap = myLibImage; - if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) - { - aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); - if (aTmpBitmap == NULL) - { - return false; - } - } - - if (FreeImage_GetBPP (aTmpBitmap) != 24) - { - FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap); - if (aTmpBitmap != myLibImage) - { - FreeImage_Unload (aTmpBitmap); - } - if (aTmpBitmap24 == NULL) - { - return false; - } - aTmpBitmap = aTmpBitmap24; - } - - // need conversion to image with palette (requires 24bit bitmap) - anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT); - if (aTmpBitmap != myLibImage) - { - FreeImage_Unload (aTmpBitmap); - } - break; - } - case FIF_HDR: - case FIF_EXR: - { - if (Format() == Image_Format_Gray - || Format() == Image_Format_Alpha) - { - anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT); - } - else if (Format() == Image_Format_RGBA - || Format() == Image_Format_BGRA) - { - anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF); - } - else - { - FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage); - if (aImgTypeFI != FIT_RGBF - && aImgTypeFI != FIT_RGBAF - && aImgTypeFI != FIT_FLOAT) - { - anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF); - } - } - break; - } - default: - { - if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) - { - anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); - if (anImageToDump == NULL) - { - return false; - } - } - - if (FreeImage_GetBPP (anImageToDump) != 24) - { - FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump); - if (anImageToDump != myLibImage) - { - FreeImage_Unload (anImageToDump); - } - if (aTmpBitmap24 == NULL) - { - return false; - } - anImageToDump = aTmpBitmap24; - } - break; - } - } - - if (anImageToDump == NULL) - { - return false; - } - -#ifdef _WIN32 - bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString()) != FALSE); -#else - bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE); -#endif - if (anImageToDump != myLibImage) - { - FreeImage_Unload (anImageToDump); - } - return isSaved; - -#elif defined(HAVE_WINCODEC) - TCollection_AsciiString aFileNameLower = theFileName; aFileNameLower.LowerCase(); - GUID aFileFormat = getNullGuid(); - if (aFileNameLower.EndsWith (".ppm")) - { - return savePPM (theFileName); - } - else if (aFileNameLower.EndsWith (".bmp")) - { - aFileFormat = GUID_ContainerFormatBmp; - } - else if (aFileNameLower.EndsWith (".png")) - { - aFileFormat = GUID_ContainerFormatPng; - } - else if (aFileNameLower.EndsWith (".jpg") - || aFileNameLower.EndsWith (".jpeg")) + if (aFileNameLower.EndsWith (".ppm") + || myLibImage.IsNull()) { - aFileFormat = GUID_ContainerFormatJpeg; - } - else if (aFileNameLower.EndsWith (".tiff")) - { - aFileFormat = GUID_ContainerFormatTiff; - } - else if (aFileNameLower.EndsWith (".gif")) - { - aFileFormat = GUID_ContainerFormatGif; - } - - if (aFileFormat == getNullGuid()) - { - Message::DefaultMessenger()->Send ("Error: unsupported image format", Message_Fail); - return false; - } - - Image_ComPtr aWicImgFactory; - CoInitializeEx (NULL, COINIT_MULTITHREADED); - if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail); - return false; - } - - Image_ComPtr aWicFileStream; - Image_ComPtr aWicEncoder; - const TCollection_ExtendedString aFileNameW (theFileName); - if (aWicImgFactory->CreateStream (&aWicFileStream.ChangePtr()) != S_OK - || aWicFileStream->InitializeFromFilename (aFileNameW.ToWideString(), GENERIC_WRITE) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot create WIC File Stream", Message_Fail); - return false; - } - if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK - || aWicEncoder->Initialize (aWicFileStream.get(), WICBitmapEncoderNoCache) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot create WIC Encoder", Message_Fail); - return false; - } - - const WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat); - if (aWicPixelFormat == getNullGuid()) - { - Message::DefaultMessenger()->Send ("Error: unsupported pixel format", Message_Fail); - return false; - } - - WICPixelFormatGUID aWicPixelFormatRes = aWicPixelFormat; - Image_ComPtr aWicFrameEncode; - if (aWicEncoder->CreateNewFrame (&aWicFrameEncode.ChangePtr(), NULL) != S_OK - || aWicFrameEncode->Initialize (NULL) != S_OK - || aWicFrameEncode->SetSize ((UINT )SizeX(), (UINT )SizeY()) != S_OK - || aWicFrameEncode->SetPixelFormat (&aWicPixelFormatRes) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot create WIC Frame", Message_Fail); - return false; - } - - if (aWicPixelFormatRes != aWicPixelFormat) - { - Message::DefaultMessenger()->Send ("Error: pixel format is unsupported by image format", Message_Fail); - return false; - } - - if (IsTopDown()) - { - if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )Data()) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail); - return false; - } - } - else - { - for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) + if (!aFileNameLower.EndsWith (".ppm")) { - if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )Row (aRow)) != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail); - return false; - } + Message::DefaultMessenger()->Send ("Image_AlienPixMap, no image library available! Image saved in PPM format.", Message_Warning); } - } - - if (aWicFrameEncode->Commit() != S_OK - || aWicEncoder->Commit() != S_OK) - { - Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC Frame", Message_Fail); - return false; - } - if (aWicFileStream->Commit (STGC_DEFAULT) != S_OK) - { - //Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC File Stream", Message_Fail); - //return false; - } - return true; -#else - const Standard_Integer aLen = theFileName.Length(); - if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.') - && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 ) - { return savePPM (theFileName); } -#ifdef OCCT_DEBUG - std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n"; -#endif - return savePPM (theFileName); -#endif + + return myLibImage->Save (theFileName); } // ======================================================================= // function : AdjustGamma // purpose : // ======================================================================= -bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr) +bool Image_AlienPixMap::AdjustGamma (Standard_Real theGammaCorr) { -#ifdef HAVE_FREEIMAGE - return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE; -#else - (void )theGammaCorr; - return false; -#endif + return !myLibImage.IsNull() + && myLibImage->AdjustGamma (theGammaCorr); } diff --git a/src/Image/Image_AlienPixMap.hxx b/src/Image/Image_AlienPixMap.hxx index 14b1f40378..088055df7f 100644 --- a/src/Image/Image_AlienPixMap.hxx +++ b/src/Image/Image_AlienPixMap.hxx @@ -16,28 +16,29 @@ #ifndef _Image_AlienPixMap_H__ #define _Image_AlienPixMap_H__ -#include - -class TCollection_AsciiString; -struct FIBITMAP; +#include //! Image class that support file reading/writing operations using auxiliary image library. -//! Supported image formats: -//! - *.bmp - bitmap image, lossless format without compression. -//! - *.ppm - PPM (Portable Pixmap Format), lossless format without compression. -//! - *.png - PNG (Portable Network Graphics) lossless format with compression. -//! - *.jpg, *.jpe, *.jpeg - JPEG/JIFF (Joint Photographic Experts Group) lossy format (compressed with quality losses). YUV color space used (automatically converted from/to RGB). -//! - *.tif, *.tiff - TIFF (Tagged Image File Format). -//! - *.tga - TGA (Truevision Targa Graphic), lossless format. -//! - *.gif - GIF (Graphical Interchange Format), lossy format. Color stored using palette (up to 256 distinct colors). -//! - *.exr - OpenEXR high dynamic-range format (supports float pixel formats). -class Image_AlienPixMap : public Image_PixMap +//! This is a wrapper over Image_FreeImage or Image_WinCodec basing on availability. +class Image_AlienPixMap : public Image_AlienPixMapI { - DEFINE_STANDARD_RTTIEXT(Image_AlienPixMap, Image_PixMap) + DEFINE_STANDARD_RTTIEXT(Image_AlienPixMap, Image_AlienPixMapI) public: //! Return default rows order used by underlying image library. Standard_EXPORT static bool IsTopDownDefault(); + + //! Create default instance of available image library or NULL if no library available. + Standard_EXPORT static Handle(Image_AlienPixMapI) CreateDefault(); + + //! Setup default image library to be used as factory. + //! Note that access to the factory is not protected by mutex, + //! make sure to call this method at the early application startup stage before using. + //! In this way, application might provide image library replacement implementing + //! image reading/writing operations which will be used by standard image tools within OCCT + //! (like image dump or texture loads). + Standard_EXPORT static void SetDefaultFactory (const Handle(Image_AlienPixMapI)& theLibrary); + public: //! Empty constructor. @@ -46,67 +47,64 @@ public: //! Destructor Standard_EXPORT virtual ~Image_AlienPixMap(); - //! Read image data from file. - bool Load (const TCollection_AsciiString& theFileName) - { - return Load (NULL, 0, theFileName); - } + using Image_AlienPixMapI::Load; //! Read image data from stream. - Standard_EXPORT bool Load (std::istream& theStream, - const TCollection_AsciiString& theFileName); + Standard_EXPORT virtual bool Load (std::istream& theStream, + const TCollection_AsciiString& theFileName) Standard_OVERRIDE; //! Read image data from memory buffer. //! @param theData memory pointer to read from; //! when NULL, function will attempt to open theFileName file //! @param theLength memory buffer length //! @param theFileName optional file name - Standard_EXPORT bool Load (const Standard_Byte* theData, - Standard_Size theLength, - const TCollection_AsciiString& theFileName); + Standard_EXPORT virtual bool Load (const Standard_Byte* theData, + Standard_Size theLength, + const TCollection_AsciiString& theFileName) Standard_OVERRIDE; //! Write image data to file using file extension to determine compression format. - Standard_EXPORT bool Save (const TCollection_AsciiString& theFileName); + Standard_EXPORT virtual bool Save (const TCollection_AsciiString& theFileName) Standard_OVERRIDE; //! Initialize image plane with required dimensions. - //! thePixelFormat - if specified pixel format doesn't supported by image library - //! than nearest supported will be used instead! - //! theSizeRowBytes - may be ignored by this class and required alignemnt will be used instead! + //! @param thePixelFormat if specified pixel format doesn't supported by image library + //! than nearest supported will be used instead! + //! @param theSizeX image width + //! @param theSizeY image height + //! @param theSizeRowBytes may be ignored by this class and required alignment will be used instead! Standard_EXPORT virtual bool InitTrash (Image_Format thePixelFormat, const Standard_Size theSizeX, const Standard_Size theSizeY, const Standard_Size theSizeRowBytes = 0) Standard_OVERRIDE; - //! Initialize by copying data. - Standard_EXPORT virtual bool InitCopy (const Image_PixMap& theCopy) Standard_OVERRIDE; - //! Method correctly deallocate internal buffer. Standard_EXPORT virtual void Clear() Standard_OVERRIDE; //! Performs gamma correction on image. //! theGamma - gamma value to use; a value of 1.0 leaves the image alone - Standard_EXPORT bool AdjustGamma (const Standard_Real theGammaCorr); + Standard_EXPORT virtual bool AdjustGamma (Standard_Real theGammaCorr) Standard_OVERRIDE; -private: - - FIBITMAP* myLibImage; + //! Setup scanlines order in memory - top-down or bottom-up. + virtual void SetTopDown (bool theIsTopDown) Standard_OVERRIDE + { + if (!myLibImage.IsNull()) + { + myLibImage->SetTopDown (theIsTopDown); + } + base_type::SetTopDown (theIsTopDown); + } private: + //! Return NULL. + Handle(Image_AlienPixMapI) createDefault() const Standard_OVERRIDE { return Handle(Image_AlienPixMapI)(); } + //! Copying allowed only within Handles Image_AlienPixMap (const Image_AlienPixMap& ); Image_AlienPixMap& operator= (const Image_AlienPixMap& ); - //! Wrapper initialization is disallowed for this class (will return false in any case)! - //! Use only copying and allocation initializers. - Standard_EXPORT virtual bool InitWrapper (Image_Format thePixelFormat, - Standard_Byte* theDataPtr, - const Standard_Size theSizeX, - const Standard_Size theSizeY, - const Standard_Size theSizeRowBytes) Standard_OVERRIDE; +private: - //! Built-in PPM export - Standard_EXPORT bool savePPM (const TCollection_AsciiString& theFileName) const; + Handle(Image_AlienPixMapI) myLibImage; }; diff --git a/src/Image/Image_AlienPixMapI.cxx b/src/Image/Image_AlienPixMapI.cxx new file mode 100644 index 0000000000..52c3c3f819 --- /dev/null +++ b/src/Image/Image_AlienPixMapI.cxx @@ -0,0 +1,151 @@ +// Created on: 2010-09-16 +// Created by: KGV +// Copyright (c) 2010-2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMapI, Image_PixMap) + +// ======================================================================= +// function : InitWrapper +// purpose : +// ======================================================================= +bool Image_AlienPixMapI::InitWrapper (Image_Format, + Standard_Byte*, + const Standard_Size, + const Standard_Size, + const Standard_Size) +{ + Clear(); + return false; +} + +// ======================================================================= +// function : InitCopy +// purpose : +// ======================================================================= +bool Image_AlienPixMapI::InitCopy (const Image_PixMap& theCopy) +{ + if (&theCopy == this) + { + // self-copying disallowed + return false; + } + if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes())) + { + return false; + } + + if (myImgFormat == theCopy.Format()) + { + if (SizeRowBytes() == theCopy.SizeRowBytes() + && TopDownInc() == theCopy.TopDownInc()) + { + // copy with one call + memcpy (ChangeData(), theCopy.Data(), std::min (SizeBytes(), theCopy.SizeBytes())); + return true; + } + + // copy row-by-row + const Standard_Size aRowSizeBytes = std::min (SizeRowBytes(), theCopy.SizeRowBytes()); + for (Standard_Size aRow = 0; aRow < myData.SizeY; ++aRow) + { + memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes); + } + return true; + } + + // pixel format conversion required + Clear(); + return false; +} + +// ======================================================================= +// function : loadStreamToBuffer +// purpose : +// ======================================================================= +bool Image_AlienPixMapI::loadStreamToBuffer (std::istream& theStream, + const TCollection_AsciiString& theFileName) +{ + Clear(); + + const std::streamoff aStart = theStream.tellg(); + theStream.seekg (0, std::ios::end); + const Standard_Integer aLen = Standard_Integer(theStream.tellg() - aStart); + theStream.seekg (aStart); + if (aLen <= 0) + { + Message::DefaultMessenger()->Send ("Error: empty stream", Message_Fail); + return false; + } + + NCollection_Array1 aBuff (1, aLen); + if (!theStream.read ((char* )&aBuff.ChangeFirst(), aBuff.Size())) + { + Message::DefaultMessenger()->Send ("Error: unable to read stream", Message_Fail); + return false; + } + + return Load (&aBuff.ChangeFirst(), aBuff.Size(), theFileName); +} + +// ======================================================================= +// function : savePPM +// purpose : +// ======================================================================= +bool Image_AlienPixMapI::savePPM (const TCollection_AsciiString& theFileName) const +{ + if (IsEmpty()) + { + return false; + } + + // Open file + FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb"); + if (aFile == NULL) + { + return false; + } + + // Write header + fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY()); + fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n"); + + // Write pixel data + Standard_Byte aByte; + for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) + { + for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol) + { + // extremely SLOW but universal (implemented for all supported pixel formats) + const Quantity_ColorRGBA aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow); + aByte = Standard_Byte(aColor.GetRGB().Red() * 255.0); fwrite (&aByte, 1, 1, aFile); + aByte = Standard_Byte(aColor.GetRGB().Green() * 255.0); fwrite (&aByte, 1, 1, aFile); + aByte = Standard_Byte(aColor.GetRGB().Blue() * 255.0); fwrite (&aByte, 1, 1, aFile); + } + } + + // Close file + fclose (aFile); + return true; +} diff --git a/src/Image/Image_AlienPixMapI.hxx b/src/Image/Image_AlienPixMapI.hxx new file mode 100644 index 0000000000..e94684dbe7 --- /dev/null +++ b/src/Image/Image_AlienPixMapI.hxx @@ -0,0 +1,98 @@ +// Created on: 2012-07-18 +// Created by: Kirill GAVRILOV +// Copyright (c) 2012-2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Image_AlienPixMapI_HeaderFile +#define _Image_AlienPixMapI_HeaderFile + +#include +#include + +//! Interface for reading/writing image files. +class Image_AlienPixMapI : public Image_PixMap +{ + DEFINE_STANDARD_RTTIEXT(Image_AlienPixMapI, Image_PixMap) +public: + + //! Empty constructor. + Image_AlienPixMapI() {} + + //! Read image data from file. + bool Load (const TCollection_AsciiString& theFileName) + { + return Load (NULL, 0, theFileName); + } + + //! Read image data from stream. + virtual bool Load (std::istream& theStream, + const TCollection_AsciiString& theFileName) = 0; + + //! Read image data from memory buffer. + //! @param theData memory pointer to read from; + //! when NULL, function will attempt to open theFileName file + //! @param theLength memory buffer length + //! @param theFileName optional file name + virtual bool Load (const Standard_Byte* theData, + Standard_Size theLength, + const TCollection_AsciiString& theFileName) = 0; + + //! Write image data to file using file extension to determine compression format. + virtual bool Save (const TCollection_AsciiString& theFileName) = 0; + + //! Performs gamma correction on image. + //! theGamma - gamma value to use; a value of 1.0 leaves the image alone + virtual bool AdjustGamma (Standard_Real theGammaCorr) { (void )theGammaCorr; return false; } + + //! Initializes image data as copy of another image. + Standard_EXPORT virtual bool InitCopy (const Image_PixMap& theCopy) Standard_OVERRIDE; + +public: + + //! Create default instance of this class. + virtual Handle(Image_AlienPixMapI) createDefault() const = 0; + +protected: + + //! Fallback copying stream data into transient buffer + Standard_EXPORT bool loadStreamToBuffer (std::istream& theStream, + const TCollection_AsciiString& theFileName); + + //! Built-in PPM export + Standard_EXPORT bool savePPM (const TCollection_AsciiString& theFileName) const; + + //! Wrapper initialization for sub-classes. + bool initWrapper (Image_Format thePixelFormat, + Standard_Byte* theDataPtr, + Standard_Size theSizeX, + Standard_Size theSizeY, + Standard_Size theSizeRowBytes) + { + return Image_PixMap::InitWrapper (thePixelFormat, theDataPtr, theSizeX, theSizeY, theSizeRowBytes); + } + +private: + + //! Wrapper initialization by user is disallowed for this class (will return false in any case)! + //! Use only copying and allocation initializers. + Standard_EXPORT virtual bool InitWrapper (Image_Format thePixelFormat, + Standard_Byte* theDataPtr, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes) Standard_OVERRIDE; + +}; + +DEFINE_STANDARD_HANDLE(Image_AlienPixMapI, Image_PixMap) + +#endif // _Image_AlienPixMapI_HeaderFile diff --git a/src/Image/Image_FreeImage.cxx b/src/Image/Image_FreeImage.cxx new file mode 100644 index 0000000000..43f034be34 --- /dev/null +++ b/src/Image/Image_FreeImage.cxx @@ -0,0 +1,655 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifdef HAVE_FREEIMAGE + #include + + #ifdef _MSC_VER + #pragma comment( lib, "FreeImage.lib" ) + #endif +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(Image_FreeImage, Image_AlienPixMapI) + +namespace +{ +#ifdef HAVE_FREEIMAGE + static Image_Format convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI, + FREE_IMAGE_COLOR_TYPE theColorTypeFI, + unsigned theBitsPerPixel) + { + switch (theFormatFI) + { + case FIT_RGBF: return Image_Format_RGBF; + case FIT_RGBAF: return Image_Format_RGBAF; + case FIT_FLOAT: return Image_Format_GrayF; + case FIT_BITMAP: + { + switch (theColorTypeFI) + { + case FIC_MINISBLACK: + { + return Image_Format_Gray; + } + case FIC_RGB: + { + if (Image_PixMap::IsBigEndianHost()) + { + return (theBitsPerPixel == 32) ? Image_Format_RGB32 : Image_Format_RGB; + } + else + { + return (theBitsPerPixel == 32) ? Image_Format_BGR32 : Image_Format_BGR; + } + } + case FIC_RGBALPHA: + { + return Image_PixMap::IsBigEndianHost() ? Image_Format_RGBA : Image_Format_BGRA; + } + default: + return Image_Format_UNKNOWN; + } + } + default: + return Image_Format_UNKNOWN; + } + } + + static FREE_IMAGE_TYPE convertToFreeFormat (Image_Format theFormat) + { + switch (theFormat) + { + case Image_Format_GrayF: + case Image_Format_AlphaF: + return FIT_FLOAT; + case Image_Format_RGBAF: + return FIT_RGBAF; + case Image_Format_RGBF: + return FIT_RGBF; + case Image_Format_RGBA: + case Image_Format_BGRA: + case Image_Format_RGB32: + case Image_Format_BGR32: + case Image_Format_RGB: + case Image_Format_BGR: + case Image_Format_Gray: + case Image_Format_Alpha: + return FIT_BITMAP; + default: + return FIT_UNKNOWN; + } + } + + //! Wrapper for accessing C++ stream from FreeImage. + class Image_FreeImageStream + { + public: + //! Construct wrapper over input stream. + Image_FreeImageStream (std::istream& theStream) + : myIStream (&theStream), myOStream (NULL), myInitPos (theStream.tellg()) {} + + //! Get io object. + FreeImageIO GetFiIO() const + { + FreeImageIO anIo; + memset (&anIo, 0, sizeof(anIo)); + if (myIStream != NULL) + { + anIo.read_proc = readProc; + anIo.seek_proc = seekProc; + anIo.tell_proc = tellProc; + } + if (myOStream != NULL) + { + anIo.write_proc = writeProc; + } + return anIo; + } + public: + //! Simulate fread(). + static unsigned int DLL_CALLCONV readProc (void* theBuffer, unsigned int theSize, unsigned int theCount, fi_handle theHandle) + { + Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle; + if (aThis->myIStream == NULL) + { + return 0; + } + + if (!aThis->myIStream->read ((char* )theBuffer, std::streamsize(theSize) * std::streamsize(theCount))) + { + //aThis->myIStream->clear(); + } + const std::streamsize aNbRead = aThis->myIStream->gcount(); + return (unsigned int )(aNbRead / theSize); + } + + //! Simulate fwrite(). + static unsigned int DLL_CALLCONV writeProc (void* theBuffer, unsigned int theSize, unsigned int theCount, fi_handle theHandle) + { + Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle; + if (aThis->myOStream != NULL + && aThis->myOStream->write ((const char* )theBuffer, std::streamsize(theSize) * std::streamsize(theCount))) + { + return theCount; + } + return 0; + } + + //! Simulate fseek(). + static int DLL_CALLCONV seekProc (fi_handle theHandle, long theOffset, int theOrigin) + { + Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle; + if (aThis->myIStream == NULL) + { + return -1; + } + + bool isSeekDone = false; + switch (theOrigin) + { + case SEEK_SET: + if (aThis->myIStream->seekg ((std::streamoff )aThis->myInitPos + theOffset, std::ios::beg)) + { + isSeekDone = true; + } + break; + case SEEK_CUR: + if (aThis->myIStream->seekg (theOffset, std::ios::cur)) + { + isSeekDone = true; + } + break; + case SEEK_END: + if (aThis->myIStream->seekg (theOffset, std::ios::end)) + { + isSeekDone = true; + } + break; + } + return isSeekDone ? 0 : -1; + } + + //! Simulate ftell(). + static long DLL_CALLCONV tellProc (fi_handle theHandle) + { + Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle; + const long aPos = aThis->myIStream != NULL ? (long )(aThis->myIStream->tellg() - aThis->myInitPos) : 0; + return aPos; + } + private: + std::istream* myIStream; + std::ostream* myOStream; + std::streampos myInitPos; + }; +#endif +} + +// ======================================================================= +// function : IsAvailable +// purpose : +// ======================================================================= +bool Image_FreeImage::IsAvailable() +{ +#if defined(HAVE_FREEIMAGE) + return true; +#else + return false; +#endif +} + +// ======================================================================= +// function : Image_FreeImage +// purpose : +// ======================================================================= +Image_FreeImage::Image_FreeImage() +: myLibImage (NULL) +{ + SetTopDown (false); +} + +// ======================================================================= +// function : ~Image_FreeImage +// purpose : +// ======================================================================= +Image_FreeImage::~Image_FreeImage() +{ + Clear(); +} + +// ======================================================================= +// function : InitTrash +// purpose : +// ======================================================================= +bool Image_FreeImage::InitTrash (Image_Format thePixelFormat, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes) +{ + Clear(); +#ifdef HAVE_FREEIMAGE + (void )theSizeRowBytes; + FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat); + int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8; + if (aFormatFI == FIT_UNKNOWN) + { + aFormatFI = FIT_BITMAP; + aBitsPerPixel = 24; + } + + FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel); + Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage), + FreeImage_GetColorType(anImage), + FreeImage_GetBPP (anImage)); + if (thePixelFormat == Image_Format_BGR32 + || thePixelFormat == Image_Format_RGB32) + { + //FreeImage_SetTransparent (anImage, FALSE); + aFormat = (aFormat == Image_Format_BGRA) ? Image_Format_BGR32 : Image_Format_RGB32; + } + + initWrapper (aFormat, FreeImage_GetBits (anImage), + FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); + SetTopDown (false); + + // assign image after wrapper initialization (virtual Clear() called inside) + myLibImage = anImage; + return true; +#else + return base_type::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes); +#endif +} + +// ======================================================================= +// function : Clear +// purpose : +// ======================================================================= +void Image_FreeImage::Clear() +{ + base_type::Clear(); +#ifdef HAVE_FREEIMAGE + if (myLibImage != NULL) + { + FreeImage_Unload (myLibImage); + myLibImage = NULL; + } +#endif +} + +// ======================================================================= +// function : Load +// purpose : +// ======================================================================= +bool Image_FreeImage::Load (const Standard_Byte* theData, + Standard_Size theLength, + const TCollection_AsciiString& theImagePath) +{ + Clear(); +#ifdef HAVE_FREEIMAGE +#ifdef _WIN32 + const TCollection_ExtendedString aFileNameW (theImagePath); +#endif + FREE_IMAGE_FORMAT aFIF = FIF_UNKNOWN; + FIMEMORY* aFiMem = NULL; + if (theData != NULL) + { + aFiMem = FreeImage_OpenMemory ((BYTE* )theData, (DWORD )theLength); + aFIF = FreeImage_GetFileTypeFromMemory (aFiMem, 0); + } + else + { + #ifdef _WIN32 + aFIF = FreeImage_GetFileTypeU (aFileNameW.ToWideString(), 0); + #else + aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0); + #endif + } + if (aFIF == FIF_UNKNOWN) + { + // no signature? try to guess the file format from the file extension + aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString()); + } + if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF)) + { + ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported file format.", + Message_Fail); + if (aFiMem != NULL) + { + FreeImage_CloseMemory (aFiMem); + } + return false; + } + + int aLoadFlags = 0; + if (aFIF == FIF_GIF) + { + // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading + aLoadFlags = GIF_PLAYBACK; + } + else if (aFIF == FIF_ICO) + { + // convert to 32bpp and create an alpha channel from the AND-mask when loading + aLoadFlags = ICO_MAKEALPHA; + } + + FIBITMAP* anImage = NULL; + if (theData != NULL) + { + anImage = FreeImage_LoadFromMemory (aFIF, aFiMem, aLoadFlags); + FreeImage_CloseMemory (aFiMem); + aFiMem = NULL; + } + else + { + #ifdef _WIN32 + anImage = FreeImage_LoadU (aFIF, aFileNameW.ToWideString(), aLoadFlags); + #else + anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags); + #endif + } + if (anImage == NULL) + { + TCollection_AsciiString aMessage = "Error: image file '"; + aMessage.AssignCat (theImagePath); + aMessage.AssignCat ("' is missing or invalid."); + ::Message::DefaultMessenger()->Send (aMessage, Message_Fail); + return false; + } + + Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage), + FreeImage_GetColorType(anImage), + FreeImage_GetBPP (anImage)); + if (aFormat == Image_Format_UNKNOWN) + { + //anImage = FreeImage_ConvertTo24Bits (anImage); + ::Message::DefaultMessenger()->Send ( TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported pixel format.", + Message_Fail); + return false; + } + + initWrapper (aFormat, FreeImage_GetBits (anImage), + FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); + SetTopDown (false); + + // assign image after wrapper initialization (virtual Clear() called inside) + myLibImage = anImage; + return true; +#else + (void )theData; + (void )theLength; + (void )theImagePath; + Message::DefaultMessenger()->Send ("Error: FreeImage library is unavailable", Message_Fail); + return false; +#endif +} + +// ======================================================================= +// function : Load +// purpose : +// ======================================================================= +bool Image_FreeImage::Load (std::istream& theStream, + const TCollection_AsciiString& theFileName) +{ + Clear(); +#ifdef HAVE_FREEIMAGE + Image_FreeImageStream aStream (theStream); + FreeImageIO aFiIO = aStream.GetFiIO(); + + FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeFromHandle (&aFiIO, &aStream, 0); + if (aFIF == FIF_UNKNOWN) + { + // no signature? try to guess the file format from the file extension + aFIF = FreeImage_GetFIFFromFilename (theFileName.ToCString()); + } + if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF)) + { + ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported file format.", + Message_Fail); + return false; + } + + int aLoadFlags = 0; + if (aFIF == FIF_GIF) + { + // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading + aLoadFlags = GIF_PLAYBACK; + } + else if (aFIF == FIF_ICO) + { + // convert to 32bpp and create an alpha channel from the AND-mask when loading + aLoadFlags = ICO_MAKEALPHA; + } + + FIBITMAP* anImage = FreeImage_LoadFromHandle (aFIF, &aFiIO, &aStream, aLoadFlags); + if (anImage == NULL) + { + ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' is missing or invalid.", + Message_Fail); + return false; + } + + Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage), + FreeImage_GetColorType(anImage), + FreeImage_GetBPP (anImage)); + if (aFormat == Image_Format_UNKNOWN) + { + ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported pixel format.", + Message_Fail); + return false; + } + + initWrapper (aFormat, FreeImage_GetBits (anImage), + FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); + SetTopDown (false); + + // assign image after wrapper initialization (virtual Clear() called inside) + myLibImage = anImage; + return true; +#else + (void )theStream; + (void )theFileName; + Message::DefaultMessenger()->Send ("Error: FreeImage library is unavailable", Message_Fail); + return false; +#endif +} + +// ======================================================================= +// function : Save +// purpose : +// ======================================================================= +bool Image_FreeImage::Save (const TCollection_AsciiString& theFileName) +{ +#ifdef HAVE_FREEIMAGE + if (myLibImage == NULL) + { + return false; + } + +#ifdef _WIN32 + const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True); + FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU (aFileNameW.ToWideString()); +#else + FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString()); +#endif + if (anImageFormat == FIF_UNKNOWN) + { +#ifdef OCCT_DEBUG + std::cerr << "Image_FreeImage, image format doesn't supported!\n"; +#endif + return false; + } + + if (IsTopDown()) + { + FreeImage_FlipVertical (myLibImage); + SetTopDown (false); + } + + // FreeImage doesn't provide flexible format conversion API + // so we should perform multiple conversions in some cases! + FIBITMAP* anImageToDump = myLibImage; + switch (anImageFormat) + { + case FIF_PNG: + case FIF_BMP: + { + if (Format() == Image_Format_BGR32 + || Format() == Image_Format_RGB32) + { + // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF + for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) + { + for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol) + { + myData.ChangeValue (aRow, aCol)[3] = 0xFF; + } + } + } + else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) + { + anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); + } + break; + } + case FIF_GIF: + { + FIBITMAP* aTmpBitmap = myLibImage; + if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) + { + aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); + if (aTmpBitmap == NULL) + { + return false; + } + } + + if (FreeImage_GetBPP (aTmpBitmap) != 24) + { + FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap); + if (aTmpBitmap != myLibImage) + { + FreeImage_Unload (aTmpBitmap); + } + if (aTmpBitmap24 == NULL) + { + return false; + } + aTmpBitmap = aTmpBitmap24; + } + + // need conversion to image with palette (requires 24bit bitmap) + anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT); + if (aTmpBitmap != myLibImage) + { + FreeImage_Unload (aTmpBitmap); + } + break; + } + case FIF_HDR: + case FIF_EXR: + { + if (Format() == Image_Format_Gray + || Format() == Image_Format_Alpha) + { + anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT); + } + else if (Format() == Image_Format_RGBA + || Format() == Image_Format_BGRA) + { + anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF); + } + else + { + FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage); + if (aImgTypeFI != FIT_RGBF + && aImgTypeFI != FIT_RGBAF + && aImgTypeFI != FIT_FLOAT) + { + anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF); + } + } + break; + } + default: + { + if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) + { + anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); + if (anImageToDump == NULL) + { + return false; + } + } + + if (FreeImage_GetBPP (anImageToDump) != 24) + { + FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump); + if (anImageToDump != myLibImage) + { + FreeImage_Unload (anImageToDump); + } + if (aTmpBitmap24 == NULL) + { + return false; + } + anImageToDump = aTmpBitmap24; + } + break; + } + } + + if (anImageToDump == NULL) + { + return false; + } + +#ifdef _WIN32 + bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString()) != FALSE); +#else + bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE); +#endif + if (anImageToDump != myLibImage) + { + FreeImage_Unload (anImageToDump); + } + return isSaved; +#else + (void )theFileName; + Message::DefaultMessenger()->Send ("Error: FreeImage library is unavailable", Message_Fail); + return false; +#endif +} + +// ======================================================================= +// function : AdjustGamma +// purpose : +// ======================================================================= +bool Image_FreeImage::AdjustGamma (const Standard_Real theGammaCorr) +{ +#ifdef HAVE_FREEIMAGE + return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE; +#else + (void )theGammaCorr; + return false; +#endif +} diff --git a/src/Image/Image_FreeImage.hxx b/src/Image/Image_FreeImage.hxx new file mode 100644 index 0000000000..9f9d86dd1c --- /dev/null +++ b/src/Image/Image_FreeImage.hxx @@ -0,0 +1,107 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Image_FreeImage_HeaderFile +#define _Image_FreeImage_HeaderFile + +#include + +struct FIBITMAP; + +//! Image class that implements file reading/writing operations using FreeImage library. +//! Supported image formats: +//! - *.bmp - bitmap image, lossless format without compression. +//! - *.ppm - PPM (Portable Pixmap Format), lossless format without compression. +//! - *.png - PNG (Portable Network Graphics) lossless format with compression. +//! - *.jpg, *.jpe, *.jpeg - JPEG/JIFF (Joint Photographic Experts Group) lossy format (compressed with quality losses). YUV color space used (automatically converted from/to RGB). +//! - *.tif, *.tiff - TIFF (Tagged Image File Format). +//! - *.tga - TGA (Truevision Targa Graphic), lossless format. +//! - *.gif - GIF (Graphical Interchange Format), lossy format. Color stored using palette (up to 256 distinct colors). +//! - *.exr - OpenEXR high dynamic-range format (supports float pixel formats). +class Image_FreeImage : public Image_AlienPixMapI +{ + DEFINE_STANDARD_RTTIEXT(Image_FreeImage, Image_AlienPixMapI) +public: + + //! Return TRUE if FreeImage library is available. + Standard_EXPORT static bool IsAvailable(); + + //! Return default rows order used by FreeImage library, which is Bottom-Up. + static bool IsTopDownDefault() { return false; } +public: + + //! Empty constructor. + Standard_EXPORT Image_FreeImage(); + + //! Destructor + Standard_EXPORT virtual ~Image_FreeImage(); + + using Image_AlienPixMapI::Load; + + //! Read image data from stream. + Standard_EXPORT virtual bool Load (std::istream& theStream, + const TCollection_AsciiString& theFileName) Standard_OVERRIDE; + + //! Read image data from memory buffer. + //! @param theData memory pointer to read from; + //! when NULL, function will attempt to open theFileName file + //! @param theLength memory buffer length + //! @param theFileName optional file name + Standard_EXPORT virtual bool Load (const Standard_Byte* theData, + Standard_Size theLength, + const TCollection_AsciiString& theFileName) Standard_OVERRIDE; + + //! Write image data to file using file extension to determine compression format. + Standard_EXPORT virtual bool Save (const TCollection_AsciiString& theFileName) Standard_OVERRIDE; + + //! Initialize image plane with required dimensions. + //! @param thePixelFormat if specified pixel format doesn't supported by image library + //! than nearest supported will be used instead! + //! @param theSizeX image width + //! @param theSizeY image height + //! @param theSizeRowBytes ignored parameter, 4-bytes alignment is enforced by FreeImage library + Standard_EXPORT virtual bool InitTrash (Image_Format thePixelFormat, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes = 0) Standard_OVERRIDE; + + //! Method correctly deallocate internal buffer. + Standard_EXPORT virtual void Clear() Standard_OVERRIDE; + + //! Performs gamma correction on image. + //! theGamma - gamma value to use; a value of 1.0 leaves the image alone + Standard_EXPORT virtual bool AdjustGamma (Standard_Real theGammaCorr) Standard_OVERRIDE; + +public: + + //! Create default instance of this class. + virtual Handle(Image_AlienPixMapI) createDefault() const Standard_OVERRIDE + { + return new Image_FreeImage(); + } + +private: + + //! Copying allowed only within Handles + Image_FreeImage (const Image_FreeImage& ); + Image_FreeImage& operator= (const Image_FreeImage& ); + +private: + + FIBITMAP* myLibImage; + +}; + +DEFINE_STANDARD_HANDLE(Image_FreeImage, Image_AlienPixMapI) + +#endif // _Image_FreeImage_HeaderFile diff --git a/src/Image/Image_PixMap.hxx b/src/Image/Image_PixMap.hxx index a87ac62be2..bbfd3f3e72 100644 --- a/src/Image/Image_PixMap.hxx +++ b/src/Image/Image_PixMap.hxx @@ -174,7 +174,7 @@ public: //! @name low-level API for batch-processing (pixels reading / compariso //! Setup scanlines order in memory - top-down or bottom-up. //! Drawers should explicitly specify this value if current state IsTopDown() was ignored! //! @param theIsTopDown top-down flag - inline void SetTopDown (const bool theIsTopDown) + virtual void SetTopDown (bool theIsTopDown) { myData.SetTopDown (theIsTopDown); } diff --git a/src/Image/Image_WinCodec.cxx b/src/Image/Image_WinCodec.cxx new file mode 100644 index 0000000000..988ebe5e08 --- /dev/null +++ b/src/Image/Image_WinCodec.cxx @@ -0,0 +1,451 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#if !defined(HAVE_FREEIMAGE) && defined(_WIN32) + #define HAVE_WINCODEC +#endif + +#if defined(HAVE_WINCODEC) + //#include + #include + #undef min + #undef max + + #ifdef _MSC_VER + #pragma comment( lib, "Ole32.lib" ) + #endif +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(Image_WinCodec, Image_AlienPixMapI) + +namespace +{ +#if defined(HAVE_WINCODEC) + + //! Return a zero GUID + static GUID getNullGuid() + { + GUID aGuid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }; + return aGuid; + } + + //! Sentry over IUnknown pointer. + template class Image_ComPtr + { + public: + //! Empty constructor. + Image_ComPtr() + : myPtr (NULL) {} + + //! Destructor. + ~Image_ComPtr() + { + Nullify(); + } + + //! Return TRUE if pointer is NULL. + bool IsNull() const { return myPtr == NULL; } + + //! Release the pointer. + void Nullify() + { + if (myPtr != NULL) + { + myPtr->Release(); + myPtr = NULL; + } + } + + //! Return pointer for initialization. + T*& ChangePtr() + { + Standard_ASSERT_RAISE (myPtr == NULL, "Pointer cannot be initialized twice!"); + return myPtr; + } + + //! Return pointer. + T* get() { return myPtr; } + + //! Return pointer. + T* operator->() { return get(); } + + //! Cast handle to contained type + T& operator*() { return *get(); } + + private: + T* myPtr; + }; + + //! Convert WIC GUID to Image_Format. + static Image_Format convertFromWicFormat (const WICPixelFormatGUID& theFormat) + { + if (theFormat == GUID_WICPixelFormat32bppBGRA) + { + return Image_Format_BGRA; + } + else if (theFormat == GUID_WICPixelFormat32bppBGR) + { + return Image_Format_BGR32; + } + else if (theFormat == GUID_WICPixelFormat24bppRGB) + { + return Image_Format_RGB; + } + else if (theFormat == GUID_WICPixelFormat24bppBGR) + { + return Image_Format_BGR; + } + else if (theFormat == GUID_WICPixelFormat8bppGray) + { + return Image_Format_Gray; + } + return Image_Format_UNKNOWN; + } + + //! Convert Image_Format to WIC GUID. + static WICPixelFormatGUID convertToWicFormat (Image_Format theFormat) + { + switch (theFormat) + { + case Image_Format_BGRA: return GUID_WICPixelFormat32bppBGRA; + case Image_Format_BGR32: return GUID_WICPixelFormat32bppBGR; + case Image_Format_RGB: return GUID_WICPixelFormat24bppRGB; + case Image_Format_BGR: return GUID_WICPixelFormat24bppBGR; + case Image_Format_Gray: return GUID_WICPixelFormat8bppGray; + case Image_Format_Alpha: return GUID_WICPixelFormat8bppGray; // GUID_WICPixelFormat8bppAlpha + case Image_Format_GrayF: // GUID_WICPixelFormat32bppGrayFloat + case Image_Format_AlphaF: + case Image_Format_RGBAF: // GUID_WICPixelFormat128bppRGBAFloat + case Image_Format_RGBF: // GUID_WICPixelFormat96bppRGBFloat + case Image_Format_RGBA: // GUID_WICPixelFormat32bppRGBA + case Image_Format_RGB32: // GUID_WICPixelFormat32bppRGB + default: + return getNullGuid(); + } + } + +#endif +} + +// ======================================================================= +// function : IsAvailable +// purpose : +// ======================================================================= +bool Image_WinCodec::IsAvailable() +{ +#if defined(HAVE_WINCODEC) + return true; +#else + return false; +#endif +} + +// ======================================================================= +// function : Image_WinCodec +// purpose : +// ======================================================================= +Image_WinCodec::Image_WinCodec() +{ + SetTopDown (true); +} + +// ======================================================================= +// function : ~Image_WinCodec +// purpose : +// ======================================================================= +Image_WinCodec::~Image_WinCodec() +{ + Clear(); +} + +// ======================================================================= +// function : InitTrash +// purpose : +// ======================================================================= +bool Image_WinCodec::InitTrash (Image_Format thePixelFormat, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes) +{ + Clear(); + + Image_Format aFormat = thePixelFormat; + switch (aFormat) + { + case Image_Format_RGB: + aFormat = Image_Format_BGR; + break; + case Image_Format_RGB32: + aFormat = Image_Format_BGR32; + break; + case Image_Format_RGBA: + aFormat = Image_Format_BGRA; + break; + default: + break; + } + + if (!base_type::InitTrash (aFormat, theSizeX, theSizeY, theSizeRowBytes)) + { + return false; + } + SetTopDown (true); + return true; +} + +// ======================================================================= +// function : Load +// purpose : +// ======================================================================= +bool Image_WinCodec::Load (const Standard_Byte* theData, + Standard_Size theLength, + const TCollection_AsciiString& theFileName) +{ + Clear(); +#if defined(HAVE_WINCODEC) + Image_ComPtr aWicImgFactory; + CoInitializeEx (NULL, COINIT_MULTITHREADED); + if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail); + return false; + } + + Image_ComPtr aWicDecoder; + Image_ComPtr aWicStream; + if (theData != NULL) + { + if (aWicImgFactory->CreateStream (&aWicStream.ChangePtr()) != S_OK + || aWicStream->InitializeFromMemory ((BYTE* )theData, (DWORD )theLength) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Stream", Message_Fail); + return false; + } + if (aWicImgFactory->CreateDecoderFromStream (aWicStream.get(), NULL, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail); + return false; + } + } + else + { + const TCollection_ExtendedString aFileNameW (theFileName); + if (aWicImgFactory->CreateDecoderFromFilename (aFileNameW.ToWideString(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail); + return false; + } + } + + UINT aFrameCount = 0, aFrameSizeX = 0, aFrameSizeY = 0; + WICPixelFormatGUID aWicPixelFormat = getNullGuid(); + Image_ComPtr aWicFrameDecode; + if (aWicDecoder->GetFrameCount (&aFrameCount) != S_OK + || aFrameCount < 1 + || aWicDecoder->GetFrame (0, &aWicFrameDecode.ChangePtr()) != S_OK + || aWicFrameDecode->GetSize (&aFrameSizeX, &aFrameSizeY) != S_OK + || aWicFrameDecode->GetPixelFormat (&aWicPixelFormat)) + { + Message::DefaultMessenger()->Send ("Error: cannot get WIC Image Frame", Message_Fail); + return false; + } + + Image_ComPtr aWicConvertedFrame; + Image_Format aPixelFormat = convertFromWicFormat (aWicPixelFormat); + if (aPixelFormat == Image_Format_UNKNOWN) + { + aPixelFormat = Image_Format_RGB; + if (aWicImgFactory->CreateFormatConverter (&aWicConvertedFrame.ChangePtr()) != S_OK + || aWicConvertedFrame->Initialize (aWicFrameDecode.get(), convertToWicFormat (aPixelFormat), WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot convert WIC Image Frame to RGB format", Message_Fail); + return false; + } + aWicFrameDecode.Nullify(); + } + + if (!base_type::InitTrash (aPixelFormat, aFrameSizeX, aFrameSizeY)) + { + Message::DefaultMessenger()->Send ("Error: cannot initialize memory for image", Message_Fail); + return false; + } + + IWICBitmapSource* aWicSrc = aWicFrameDecode.get(); + if(!aWicConvertedFrame.IsNull()) + { + aWicSrc = aWicConvertedFrame.get(); + } + if (aWicSrc->CopyPixels (NULL, (UINT )SizeRowBytes(), (UINT )SizeBytes(), ChangeData()) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot copy pixels from WIC Image", Message_Fail); + return false; + } + SetTopDown (true); + return true; +#else + (void )theData; + (void )theLength; + (void )theFileName; + Message::DefaultMessenger()->Send ("Error: WinCodec image library is unavailable", Message_Fail); + return false; +#endif +} + +// ======================================================================= +// function : Load +// purpose : +// ======================================================================= +bool Image_WinCodec::Load (std::istream& theStream, + const TCollection_AsciiString& theFilePath) +{ + return loadStreamToBuffer (theStream, theFilePath); +} + +// ======================================================================= +// function : Save +// purpose : +// ======================================================================= +bool Image_WinCodec::Save (const TCollection_AsciiString& theFileName) +{ +#if defined(HAVE_WINCODEC) + TCollection_AsciiString aFileNameLower = theFileName; + aFileNameLower.LowerCase(); + GUID aFileFormat = getNullGuid(); + if (aFileNameLower.EndsWith (".ppm")) + { + return savePPM (theFileName); + } + else if (aFileNameLower.EndsWith (".bmp")) + { + aFileFormat = GUID_ContainerFormatBmp; + } + else if (aFileNameLower.EndsWith (".png")) + { + aFileFormat = GUID_ContainerFormatPng; + } + else if (aFileNameLower.EndsWith (".jpg") + || aFileNameLower.EndsWith (".jpeg")) + { + aFileFormat = GUID_ContainerFormatJpeg; + } + else if (aFileNameLower.EndsWith (".tiff")) + { + aFileFormat = GUID_ContainerFormatTiff; + } + else if (aFileNameLower.EndsWith (".gif")) + { + aFileFormat = GUID_ContainerFormatGif; + } + + if (aFileFormat == getNullGuid()) + { + Message::DefaultMessenger()->Send ("Error: unsupported image format", Message_Fail); + return false; + } + + Image_ComPtr aWicImgFactory; + CoInitializeEx (NULL, COINIT_MULTITHREADED); + if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail); + return false; + } + + Image_ComPtr aWicFileStream; + Image_ComPtr aWicEncoder; + const TCollection_ExtendedString aFileNameW (theFileName); + if (aWicImgFactory->CreateStream (&aWicFileStream.ChangePtr()) != S_OK + || aWicFileStream->InitializeFromFilename (aFileNameW.ToWideString(), GENERIC_WRITE) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot create WIC File Stream", Message_Fail); + return false; + } + if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK + || aWicEncoder->Initialize (aWicFileStream.get(), WICBitmapEncoderNoCache) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot create WIC Encoder", Message_Fail); + return false; + } + + const WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat); + if (aWicPixelFormat == getNullGuid()) + { + Message::DefaultMessenger()->Send ("Error: unsupported pixel format", Message_Fail); + return false; + } + + WICPixelFormatGUID aWicPixelFormatRes = aWicPixelFormat; + Image_ComPtr aWicFrameEncode; + if (aWicEncoder->CreateNewFrame (&aWicFrameEncode.ChangePtr(), NULL) != S_OK + || aWicFrameEncode->Initialize (NULL) != S_OK + || aWicFrameEncode->SetSize ((UINT )SizeX(), (UINT )SizeY()) != S_OK + || aWicFrameEncode->SetPixelFormat (&aWicPixelFormatRes) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot create WIC Frame", Message_Fail); + return false; + } + + if (aWicPixelFormatRes != aWicPixelFormat) + { + Message::DefaultMessenger()->Send ("Error: pixel format is unsupported by image format", Message_Fail); + return false; + } + + if (IsTopDown()) + { + if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )Data()) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail); + return false; + } + } + else + { + for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) + { + if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )Row (aRow)) != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail); + return false; + } + } + } + + if (aWicFrameEncode->Commit() != S_OK + || aWicEncoder->Commit() != S_OK) + { + Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC Frame", Message_Fail); + return false; + } + if (aWicFileStream->Commit (STGC_DEFAULT) != S_OK) + { + //Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC File Stream", Message_Fail); + //return false; + } + return true; +#else + (void )theFileName; + Message::DefaultMessenger()->Send ("Error: WinCodec image library is unavailable", Message_Fail); + return false; +#endif +} diff --git a/src/Image/Image_WinCodec.hxx b/src/Image/Image_WinCodec.hxx new file mode 100644 index 0000000000..98d8b10b89 --- /dev/null +++ b/src/Image/Image_WinCodec.hxx @@ -0,0 +1,87 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Image_WinCodec_HeaderFile +#define _Image_WinCodec_HeaderFile + +#include + +//! Image class that implements file reading/writing operations using WinCodec image library. +//! Supported image formats: +//! - *.bmp, *.png, *.jpg, *.tiff, *.gif. +class Image_WinCodec : public Image_AlienPixMapI +{ + DEFINE_STANDARD_RTTIEXT(Image_WinCodec, Image_AlienPixMapI) +public: + + //! Return TRUE if WinCodec library is available. + Standard_EXPORT static bool IsAvailable(); + + //! Return default rows order used by WinCodec library, which is Top-Down. + static bool IsTopDownDefault() { return true; } +public: + + //! Empty constructor. + Standard_EXPORT Image_WinCodec(); + + //! Destructor + Standard_EXPORT virtual ~Image_WinCodec(); + + using Image_AlienPixMapI::Load; + + //! Read image data from stream. + Standard_EXPORT virtual bool Load (std::istream& theStream, + const TCollection_AsciiString& theFileName) Standard_OVERRIDE; + + //! Read image data from memory buffer. + //! @param theData memory pointer to read from; + //! when NULL, function will attempt to open theFileName file + //! @param theLength memory buffer length + //! @param theFileName optional file name + Standard_EXPORT virtual bool Load (const Standard_Byte* theData, + Standard_Size theLength, + const TCollection_AsciiString& theFileName) Standard_OVERRIDE; + + //! Write image data to file using file extension to determine compression format. + Standard_EXPORT virtual bool Save (const TCollection_AsciiString& theFileName) Standard_OVERRIDE; + + //! Initialize image plane with required dimensions. + //! @param thePixelFormat if specified pixel format doesn't supported by image library + //! than nearest supported will be used instead! + //! @param theSizeX image width + //! @param theSizeY image height + //! @param theSizeRowBytes may be ignored by this class and required alignment will be used instead! + Standard_EXPORT virtual bool InitTrash (Image_Format thePixelFormat, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes = 0) Standard_OVERRIDE; + +public: + + //! Create default instance of this class. + virtual Handle(Image_AlienPixMapI) createDefault() const Standard_OVERRIDE + { + return new Image_WinCodec(); + } + +private: + + //! Copying allowed only within Handles + Image_WinCodec (const Image_WinCodec& ); + Image_WinCodec& operator= (const Image_WinCodec& ); + +}; + +DEFINE_STANDARD_HANDLE(Image_WinCodec, Image_AlienPixMapI) + +#endif // _Image_WinCodec_HeaderFile -- 2.39.5