]> OCCT Git - occt-copy.git/commitdiff
0030549: Coding - split Image_AlienPixMap into several classes CR30549
authorkgv <kgv@opencascade.com>
Sat, 9 Mar 2019 02:07:01 +0000 (05:07 +0300)
committerkgv <kgv@opencascade.com>
Sat, 9 Mar 2019 11:27:03 +0000 (14:27 +0300)
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
src/Image/FILES
src/Image/Image_AlienPixMap.cxx
src/Image/Image_AlienPixMap.hxx
src/Image/Image_AlienPixMapI.cxx [new file with mode: 0644]
src/Image/Image_AlienPixMapI.hxx [new file with mode: 0644]
src/Image/Image_FreeImage.cxx [new file with mode: 0644]
src/Image/Image_FreeImage.hxx [new file with mode: 0644]
src/Image/Image_PixMap.hxx
src/Image/Image_WinCodec.cxx [new file with mode: 0644]
src/Image/Image_WinCodec.hxx [new file with mode: 0644]

index 41f779650f632db5999c0e577a8b4cadb104212d..e5e7d8da39b1e3937c535ebde844b2902e6a01ff 100644 (file)
@@ -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);
 }
index 40118d5bcaffecd2c334a607ac988d019e6509f3..dc19f8162d5e507a9dfe2a0729561759a1084886 100755 (executable)
@@ -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
index ba166a5fc6482c48f7f19127913aae6ca66e8fba..eee10a63f5b9800b3f6ddc1b73980aeb23c4180f 100644 (file)
 // 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 <FreeImage.h>
+#include <Image_AlienPixMap.hxx>
 
-  #ifdef _MSC_VER
-    #pragma comment( lib, "FreeImage.lib" )
-  #endif
-#elif defined(HAVE_WINCODEC)
-  //#include <initguid.h>
-  #include <wincodec.h>
-  #undef min
-  #undef max
-#endif
+#include <Image_FreeImage.hxx>
+#include <Image_WinCodec.hxx>
 
-#include <Image_AlienPixMap.hxx>
-#include <gp.hxx>
 #include <Message.hxx>
 #include <Message_Messenger.hxx>
-#include <NCollection_Array1.hxx>
-#include <Standard_ArrayStreamBuffer.hxx>
 #include <TCollection_AsciiString.hxx>
 #include <TCollection_ExtendedString.hxx>
-#include <OSD_OpenFile.hxx>
-#include <fstream>
-#include <algorithm>
 
 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 T> 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<IWICImagingFactory> 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<IWICBitmapDecoder> aWicDecoder;
-  Image_ComPtr<IWICStream> 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<IWICBitmapFrameDecode> 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<IWICFormatConverter> 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<Standard_Byte> 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<IWICImagingFactory> 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<IWICStream> aWicFileStream;
-  Image_ComPtr<IWICBitmapEncoder> 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<IWICBitmapFrameEncode> 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);
 }
index 14b1f40378d2d96a0ca002df187d2a9675639173..088055df7f66fb0fcf4d01f6eb1cdf3a05f082ef 100644 (file)
 #ifndef _Image_AlienPixMap_H__
 #define _Image_AlienPixMap_H__
 
-#include <Image_PixMap.hxx>
-
-class TCollection_AsciiString;
-struct FIBITMAP;
+#include <Image_AlienPixMapI.hxx>
 
 //! 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 (file)
index 0000000..52c3c3f
--- /dev/null
@@ -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 <Image_AlienPixMapI.hxx>
+#include <gp.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <NCollection_Array1.hxx>
+#include <TCollection_AsciiString.hxx>
+#include <TCollection_ExtendedString.hxx>
+#include <OSD_OpenFile.hxx>
+#include <fstream>
+#include <algorithm>
+
+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<Standard_Byte> 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 (file)
index 0000000..e94684d
--- /dev/null
@@ -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 <Image_PixMap.hxx>
+#include <TCollection_AsciiString.hxx>
+
+//! 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 (file)
index 0000000..43f034b
--- /dev/null
@@ -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 <FreeImage.h>
+
+  #ifdef _MSC_VER
+    #pragma comment( lib, "FreeImage.lib" )
+  #endif
+#endif
+
+#include <Image_FreeImage.hxx>
+
+#include <gp.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <TCollection_AsciiString.hxx>
+#include <TCollection_ExtendedString.hxx>
+#include <OSD_OpenFile.hxx>
+#include <fstream>
+#include <algorithm>
+
+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 (file)
index 0000000..9f9d86d
--- /dev/null
@@ -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 <Image_AlienPixMapI.hxx>
+
+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
index a87ac62be2da59cb3f8c11c661b81a4514a04db4..bbfd3f3e72c8aee9ca9af6e7c299596b05f9f0e6 100644 (file)
@@ -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 (file)
index 0000000..988ebe5
--- /dev/null
@@ -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 <initguid.h>
+  #include <wincodec.h>
+  #undef min
+  #undef max
+
+  #ifdef _MSC_VER
+    #pragma comment( lib, "Ole32.lib" )
+  #endif
+#endif
+
+#include <Image_WinCodec.hxx>
+
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <TCollection_AsciiString.hxx>
+#include <TCollection_ExtendedString.hxx>
+#include <OSD_OpenFile.hxx>
+#include <fstream>
+#include <algorithm>
+
+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 T> 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<IWICImagingFactory> 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<IWICBitmapDecoder> aWicDecoder;
+  Image_ComPtr<IWICStream> 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<IWICBitmapFrameDecode> 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<IWICFormatConverter> 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<IWICImagingFactory> 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<IWICStream> aWicFileStream;
+  Image_ComPtr<IWICBitmapEncoder> 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<IWICBitmapFrameEncode> 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 (file)
index 0000000..98d8b10
--- /dev/null
@@ -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_AlienPixMapI.hxx>
+
+//! 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