1 // Created on: 2010-09-16
3 // Copyright (c) 2010-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #if !defined(HAVE_FREEIMAGE) && defined(_WIN32)
21 #include <FreeImage.h>
24 #pragma comment( lib, "FreeImage.lib" )
26 #elif defined(HAVE_WINCODEC)
28 // prevent warnings on MSVC10
29 #include <Standard_WarningsDisable.hxx>
30 #include <Standard_TypeDef.hxx>
31 #include <Standard_WarningsRestore.hxx>
36 #include <Image_AlienPixMap.hxx>
38 #include <Message.hxx>
39 #include <Message_Messenger.hxx>
40 #include <NCollection_Array1.hxx>
41 #include <Standard_ArrayStreamBuffer.hxx>
42 #include <TCollection_AsciiString.hxx>
43 #include <TCollection_ExtendedString.hxx>
44 #include <OSD_OpenFile.hxx>
49 IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap,Image_PixMap)
54 static Image_Format convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI,
55 FREE_IMAGE_COLOR_TYPE theColorTypeFI,
56 unsigned theBitsPerPixel)
60 case FIT_RGBF: return Image_Format_RGBF;
61 case FIT_RGBAF: return Image_Format_RGBAF;
62 case FIT_FLOAT: return Image_Format_GrayF;
65 switch (theColorTypeFI)
69 return Image_Format_Gray;
73 if (Image_PixMap::IsBigEndianHost())
75 return (theBitsPerPixel == 32) ? Image_Format_RGB32 : Image_Format_RGB;
79 return (theBitsPerPixel == 32) ? Image_Format_BGR32 : Image_Format_BGR;
84 return Image_PixMap::IsBigEndianHost() ? Image_Format_RGBA : Image_Format_BGRA;
87 return Image_Format_UNKNOWN;
91 return Image_Format_UNKNOWN;
95 static FREE_IMAGE_TYPE convertToFreeFormat (Image_Format theFormat)
99 case Image_Format_GrayF:
100 case Image_Format_AlphaF:
102 case Image_Format_RGBAF:
104 case Image_Format_RGBF:
106 case Image_Format_RGBA:
107 case Image_Format_BGRA:
108 case Image_Format_RGB32:
109 case Image_Format_BGR32:
110 case Image_Format_RGB:
111 case Image_Format_BGR:
112 case Image_Format_Gray:
113 case Image_Format_Alpha:
120 //! Wrapper for accessing C++ stream from FreeImage.
121 class Image_FreeImageStream
124 //! Construct wrapper over input stream.
125 Image_FreeImageStream (std::istream& theStream)
126 : myIStream (&theStream), myOStream (NULL), myInitPos (theStream.tellg()) {}
129 FreeImageIO GetFiIO() const
132 memset (&anIo, 0, sizeof(anIo));
133 if (myIStream != NULL)
135 anIo.read_proc = readProc;
136 anIo.seek_proc = seekProc;
137 anIo.tell_proc = tellProc;
139 if (myOStream != NULL)
141 anIo.write_proc = writeProc;
146 //! Simulate fread().
147 static unsigned int DLL_CALLCONV readProc (void* theBuffer, unsigned int theSize, unsigned int theCount, fi_handle theHandle)
149 Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
150 if (aThis->myIStream == NULL)
155 if (!aThis->myIStream->read ((char* )theBuffer, std::streamsize(theSize) * std::streamsize(theCount)))
157 //aThis->myIStream->clear();
159 const std::streamsize aNbRead = aThis->myIStream->gcount();
160 return (unsigned int )(aNbRead / theSize);
163 //! Simulate fwrite().
164 static unsigned int DLL_CALLCONV writeProc (void* theBuffer, unsigned int theSize, unsigned int theCount, fi_handle theHandle)
166 Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
167 if (aThis->myOStream != NULL
168 && aThis->myOStream->write ((const char* )theBuffer, std::streamsize(theSize) * std::streamsize(theCount)))
175 //! Simulate fseek().
176 static int DLL_CALLCONV seekProc (fi_handle theHandle, long theOffset, int theOrigin)
178 Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
179 if (aThis->myIStream == NULL)
184 bool isSeekDone = false;
188 if (aThis->myIStream->seekg ((std::streamoff )aThis->myInitPos + theOffset, std::ios::beg))
194 if (aThis->myIStream->seekg (theOffset, std::ios::cur))
200 if (aThis->myIStream->seekg (theOffset, std::ios::end))
206 return isSeekDone ? 0 : -1;
209 //! Simulate ftell().
210 static long DLL_CALLCONV tellProc (fi_handle theHandle)
212 Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
213 const long aPos = aThis->myIStream != NULL ? (long )(aThis->myIStream->tellg() - aThis->myInitPos) : 0;
217 std::istream* myIStream;
218 std::ostream* myOStream;
219 std::streampos myInitPos;
222 #elif defined(HAVE_WINCODEC)
224 //! Return a zero GUID
225 static GUID getNullGuid()
227 GUID aGuid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } };
231 //! Sentry over IUnknown pointer.
232 template<class T> class Image_ComPtr
235 //! Empty constructor.
245 //! Return TRUE if pointer is NULL.
246 bool IsNull() const { return myPtr == NULL; }
248 //! Release the pointer.
258 //! Return pointer for initialization.
261 Standard_ASSERT_RAISE (myPtr == NULL, "Pointer cannot be initialized twice!");
266 T* get() { return myPtr; }
269 T* operator->() { return get(); }
271 //! Cast handle to contained type
272 T& operator*() { return *get(); }
278 //! Convert WIC GUID to Image_Format.
279 static Image_Format convertFromWicFormat (const WICPixelFormatGUID& theFormat)
281 if (theFormat == GUID_WICPixelFormat32bppBGRA)
283 return Image_Format_BGRA;
285 else if (theFormat == GUID_WICPixelFormat32bppBGR)
287 return Image_Format_BGR32;
289 else if (theFormat == GUID_WICPixelFormat24bppRGB)
291 return Image_Format_RGB;
293 else if (theFormat == GUID_WICPixelFormat24bppBGR)
295 return Image_Format_BGR;
297 else if (theFormat == GUID_WICPixelFormat8bppGray)
299 return Image_Format_Gray;
301 return Image_Format_UNKNOWN;
304 //! Convert Image_Format to WIC GUID.
305 static WICPixelFormatGUID convertToWicFormat (Image_Format theFormat)
309 case Image_Format_BGRA: return GUID_WICPixelFormat32bppBGRA;
310 case Image_Format_BGR32: return GUID_WICPixelFormat32bppBGR;
311 case Image_Format_RGB: return GUID_WICPixelFormat24bppRGB;
312 case Image_Format_BGR: return GUID_WICPixelFormat24bppBGR;
313 case Image_Format_Gray: return GUID_WICPixelFormat8bppGray;
314 case Image_Format_Alpha: return GUID_WICPixelFormat8bppGray; // GUID_WICPixelFormat8bppAlpha
315 case Image_Format_GrayF: // GUID_WICPixelFormat32bppGrayFloat
316 case Image_Format_AlphaF:
317 case Image_Format_RGBAF: // GUID_WICPixelFormat128bppRGBAFloat
318 case Image_Format_RGBF: // GUID_WICPixelFormat96bppRGBFloat
319 case Image_Format_RGBA: // GUID_WICPixelFormat32bppRGBA
320 case Image_Format_RGB32: // GUID_WICPixelFormat32bppRGB
322 return getNullGuid();
329 // =======================================================================
330 // function : Image_AlienPixMap
332 // =======================================================================
333 Image_AlienPixMap::Image_AlienPixMap()
339 // =======================================================================
340 // function : ~Image_AlienPixMap
342 // =======================================================================
343 Image_AlienPixMap::~Image_AlienPixMap()
348 // =======================================================================
349 // function : InitWrapper
351 // =======================================================================
352 bool Image_AlienPixMap::InitWrapper (Image_Format,
362 // =======================================================================
363 // function : InitTrash
365 // =======================================================================
366 #ifdef HAVE_FREEIMAGE
367 bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat,
368 const Standard_Size theSizeX,
369 const Standard_Size theSizeY,
370 const Standard_Size /*theSizeRowBytes*/)
373 FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat);
374 int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8;
375 if (aFormatFI == FIT_UNKNOWN)
377 aFormatFI = FIT_BITMAP;
381 FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel);
382 Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
383 FreeImage_GetColorType(anImage),
384 FreeImage_GetBPP (anImage));
385 if (thePixelFormat == Image_Format_BGR32
386 || thePixelFormat == Image_Format_RGB32)
388 //FreeImage_SetTransparent (anImage, FALSE);
389 aFormat = (aFormat == Image_Format_BGRA) ? Image_Format_BGR32 : Image_Format_RGB32;
392 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
393 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
396 // assign image after wrapper initialization (virtual Clear() called inside)
397 myLibImage = anImage;
400 #elif defined(HAVE_WINCODEC)
401 bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat,
402 const Standard_Size theSizeX,
403 const Standard_Size theSizeY,
404 const Standard_Size theSizeRowBytes)
407 Image_Format aFormat = thePixelFormat;
410 case Image_Format_RGB:
411 aFormat = Image_Format_BGR;
413 case Image_Format_RGB32:
414 aFormat = Image_Format_BGR32;
416 case Image_Format_RGBA:
417 aFormat = Image_Format_BGRA;
423 if (!Image_PixMap::InitTrash (aFormat, theSizeX, theSizeY, theSizeRowBytes))
431 bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat,
432 const Standard_Size theSizeX,
433 const Standard_Size theSizeY,
434 const Standard_Size theSizeRowBytes)
436 return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes);
440 // =======================================================================
441 // function : InitCopy
443 // =======================================================================
444 bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy)
446 if (&theCopy == this)
448 // self-copying disallowed
451 if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes()))
456 if (myImgFormat == theCopy.Format())
458 if (SizeRowBytes() == theCopy.SizeRowBytes()
459 && TopDownInc() == theCopy.TopDownInc())
461 // copy with one call
462 memcpy (ChangeData(), theCopy.Data(), std::min (SizeBytes(), theCopy.SizeBytes()));
467 const Standard_Size aRowSizeBytes = std::min (SizeRowBytes(), theCopy.SizeRowBytes());
468 for (Standard_Size aRow = 0; aRow < myData.SizeY; ++aRow)
470 memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes);
475 // pixel format conversion required
480 // =======================================================================
483 // =======================================================================
484 void Image_AlienPixMap::Clear()
486 Image_PixMap::Clear();
487 #ifdef HAVE_FREEIMAGE
488 if (myLibImage != NULL)
490 FreeImage_Unload (myLibImage);
496 // =======================================================================
497 // function : IsTopDownDefault
499 // =======================================================================
500 bool Image_AlienPixMap::IsTopDownDefault()
502 #ifdef HAVE_FREEIMAGE
504 #elif defined(HAVE_WINCODEC)
511 // =======================================================================
514 // =======================================================================
515 #ifdef HAVE_FREEIMAGE
516 bool Image_AlienPixMap::Load (const Standard_Byte* theData,
517 Standard_Size theLength,
518 const TCollection_AsciiString& theImagePath)
523 const TCollection_ExtendedString aFileNameW (theImagePath);
525 FREE_IMAGE_FORMAT aFIF = FIF_UNKNOWN;
526 FIMEMORY* aFiMem = NULL;
529 aFiMem = FreeImage_OpenMemory ((BYTE* )theData, (DWORD )theLength);
530 aFIF = FreeImage_GetFileTypeFromMemory (aFiMem, 0);
535 aFIF = FreeImage_GetFileTypeU (aFileNameW.ToWideString(), 0);
537 aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0);
540 if (aFIF == FIF_UNKNOWN)
542 // no signature? try to guess the file format from the file extension
543 aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString());
545 if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
547 ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported file format.",
551 FreeImage_CloseMemory (aFiMem);
559 // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
560 aLoadFlags = GIF_PLAYBACK;
562 else if (aFIF == FIF_ICO)
564 // convert to 32bpp and create an alpha channel from the AND-mask when loading
565 aLoadFlags = ICO_MAKEALPHA;
568 FIBITMAP* anImage = NULL;
571 anImage = FreeImage_LoadFromMemory (aFIF, aFiMem, aLoadFlags);
572 FreeImage_CloseMemory (aFiMem);
578 anImage = FreeImage_LoadU (aFIF, aFileNameW.ToWideString(), aLoadFlags);
580 anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags);
585 TCollection_AsciiString aMessage = "Error: image file '";
586 aMessage.AssignCat (theImagePath);
587 aMessage.AssignCat ("' is missing or invalid.");
588 ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
592 Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
593 FreeImage_GetColorType(anImage),
594 FreeImage_GetBPP (anImage));
595 if (aFormat == Image_Format_UNKNOWN)
597 //anImage = FreeImage_ConvertTo24Bits (anImage);
598 ::Message::DefaultMessenger()->Send ( TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported pixel format.",
603 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
604 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
607 // assign image after wrapper initialization (virtual Clear() called inside)
608 myLibImage = anImage;
612 bool Image_AlienPixMap::Load (std::istream& theStream,
613 const TCollection_AsciiString& theFileName)
617 Image_FreeImageStream aStream (theStream);
618 FreeImageIO aFiIO = aStream.GetFiIO();
620 FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeFromHandle (&aFiIO, &aStream, 0);
621 if (aFIF == FIF_UNKNOWN)
623 // no signature? try to guess the file format from the file extension
624 aFIF = FreeImage_GetFIFFromFilename (theFileName.ToCString());
626 if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
628 ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported file format.",
636 // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
637 aLoadFlags = GIF_PLAYBACK;
639 else if (aFIF == FIF_ICO)
641 // convert to 32bpp and create an alpha channel from the AND-mask when loading
642 aLoadFlags = ICO_MAKEALPHA;
645 FIBITMAP* anImage = FreeImage_LoadFromHandle (aFIF, &aFiIO, &aStream, aLoadFlags);
648 ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' is missing or invalid.",
653 Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
654 FreeImage_GetColorType(anImage),
655 FreeImage_GetBPP (anImage));
656 if (aFormat == Image_Format_UNKNOWN)
658 ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported pixel format.",
663 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
664 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
667 // assign image after wrapper initialization (virtual Clear() called inside)
668 myLibImage = anImage;
672 #elif defined(HAVE_WINCODEC)
673 bool Image_AlienPixMap::Load (const Standard_Byte* theData,
674 Standard_Size theLength,
675 const TCollection_AsciiString& theFileName)
679 Image_ComPtr<IWICImagingFactory> aWicImgFactory;
680 CoInitializeEx (NULL, COINIT_MULTITHREADED);
681 if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK)
683 Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail);
687 Image_ComPtr<IWICBitmapDecoder> aWicDecoder;
688 Image_ComPtr<IWICStream> aWicStream;
691 if (aWicImgFactory->CreateStream (&aWicStream.ChangePtr()) != S_OK
692 || aWicStream->InitializeFromMemory ((BYTE* )theData, (DWORD )theLength) != S_OK)
694 Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Stream", Message_Fail);
697 if (aWicImgFactory->CreateDecoderFromStream (aWicStream.get(), NULL, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK)
699 Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail);
705 const TCollection_ExtendedString aFileNameW (theFileName);
706 if (aWicImgFactory->CreateDecoderFromFilename (aFileNameW.ToWideString(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK)
708 Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail);
713 UINT aFrameCount = 0, aFrameSizeX = 0, aFrameSizeY = 0;
714 WICPixelFormatGUID aWicPixelFormat = getNullGuid();
715 Image_ComPtr<IWICBitmapFrameDecode> aWicFrameDecode;
716 if (aWicDecoder->GetFrameCount (&aFrameCount) != S_OK
718 || aWicDecoder->GetFrame (0, &aWicFrameDecode.ChangePtr()) != S_OK
719 || aWicFrameDecode->GetSize (&aFrameSizeX, &aFrameSizeY) != S_OK
720 || aWicFrameDecode->GetPixelFormat (&aWicPixelFormat))
722 Message::DefaultMessenger()->Send ("Error: cannot get WIC Image Frame", Message_Fail);
726 Image_ComPtr<IWICFormatConverter> aWicConvertedFrame;
727 Image_Format aPixelFormat = convertFromWicFormat (aWicPixelFormat);
728 if (aPixelFormat == Image_Format_UNKNOWN)
730 aPixelFormat = Image_Format_RGB;
731 if (aWicImgFactory->CreateFormatConverter (&aWicConvertedFrame.ChangePtr()) != S_OK
732 || aWicConvertedFrame->Initialize (aWicFrameDecode.get(), convertToWicFormat (aPixelFormat), WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom) != S_OK)
734 Message::DefaultMessenger()->Send ("Error: cannot convert WIC Image Frame to RGB format", Message_Fail);
737 aWicFrameDecode.Nullify();
740 if (!Image_PixMap::InitTrash (aPixelFormat, aFrameSizeX, aFrameSizeY))
742 Message::DefaultMessenger()->Send ("Error: cannot initialize memory for image", Message_Fail);
746 IWICBitmapSource* aWicSrc = aWicFrameDecode.get();
747 if(!aWicConvertedFrame.IsNull())
749 aWicSrc = aWicConvertedFrame.get();
751 if (aWicSrc->CopyPixels (NULL, (UINT )SizeRowBytes(), (UINT )SizeBytes(), ChangeData()) != S_OK)
753 Message::DefaultMessenger()->Send ("Error: cannot copy pixels from WIC Image", Message_Fail);
759 bool Image_AlienPixMap::Load (std::istream& theStream,
760 const TCollection_AsciiString& theFilePath)
764 // fallback copying stream data into transient buffer
765 const std::streamoff aStart = theStream.tellg();
766 theStream.seekg (0, std::ios::end);
767 const Standard_Integer aLen = Standard_Integer(theStream.tellg() - aStart);
768 theStream.seekg (aStart);
771 Message::DefaultMessenger()->Send ("Error: empty stream", Message_Fail);
775 NCollection_Array1<Standard_Byte> aBuff (1, aLen);
776 if (!theStream.read ((char* )&aBuff.ChangeFirst(), aBuff.Size()))
778 Message::DefaultMessenger()->Send ("Error: unable to read stream", Message_Fail);
782 return Load (&aBuff.ChangeFirst(), aBuff.Size(), theFilePath);
785 bool Image_AlienPixMap::Load (std::istream& ,
786 const TCollection_AsciiString& )
789 Message::DefaultMessenger()->Send ("Error: no image library available", Message_Fail);
792 bool Image_AlienPixMap::Load (const Standard_Byte* ,
794 const TCollection_AsciiString& )
797 Message::DefaultMessenger()->Send ("Error: no image library available", Message_Fail);
802 // =======================================================================
803 // function : savePPM
805 // =======================================================================
806 bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const
814 FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb");
821 fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY());
822 fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n");
826 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
828 for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
830 // extremely SLOW but universal (implemented for all supported pixel formats)
831 const Quantity_ColorRGBA aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow);
832 aByte = Standard_Byte(aColor.GetRGB().Red() * 255.0); fwrite (&aByte, 1, 1, aFile);
833 aByte = Standard_Byte(aColor.GetRGB().Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
834 aByte = Standard_Byte(aColor.GetRGB().Blue() * 255.0); fwrite (&aByte, 1, 1, aFile);
843 // =======================================================================
846 // =======================================================================
847 bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName)
849 #ifdef HAVE_FREEIMAGE
850 if (myLibImage == NULL)
856 const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True);
857 FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU (aFileNameW.ToWideString());
859 FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString());
861 if (anImageFormat == FIF_UNKNOWN)
864 std::cerr << "Image_PixMap, image format doesn't supported!\n";
871 FreeImage_FlipVertical (myLibImage);
875 // FreeImage doesn't provide flexible format conversion API
876 // so we should perform multiple conversions in some cases!
877 FIBITMAP* anImageToDump = myLibImage;
878 switch (anImageFormat)
883 if (Format() == Image_Format_BGR32
884 || Format() == Image_Format_RGB32)
886 // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
887 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
889 for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
891 myData.ChangeValue (aRow, aCol)[3] = 0xFF;
895 else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
897 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
903 FIBITMAP* aTmpBitmap = myLibImage;
904 if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
906 aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
907 if (aTmpBitmap == NULL)
913 if (FreeImage_GetBPP (aTmpBitmap) != 24)
915 FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
916 if (aTmpBitmap != myLibImage)
918 FreeImage_Unload (aTmpBitmap);
920 if (aTmpBitmap24 == NULL)
924 aTmpBitmap = aTmpBitmap24;
927 // need conversion to image with palette (requires 24bit bitmap)
928 anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
929 if (aTmpBitmap != myLibImage)
931 FreeImage_Unload (aTmpBitmap);
938 if (Format() == Image_Format_Gray
939 || Format() == Image_Format_Alpha)
941 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
943 else if (Format() == Image_Format_RGBA
944 || Format() == Image_Format_BGRA)
946 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
950 FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
951 if (aImgTypeFI != FIT_RGBF
952 && aImgTypeFI != FIT_RGBAF
953 && aImgTypeFI != FIT_FLOAT)
955 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
962 if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
964 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
965 if (anImageToDump == NULL)
971 if (FreeImage_GetBPP (anImageToDump) != 24)
973 FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
974 if (anImageToDump != myLibImage)
976 FreeImage_Unload (anImageToDump);
978 if (aTmpBitmap24 == NULL)
982 anImageToDump = aTmpBitmap24;
988 if (anImageToDump == NULL)
994 bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString()) != FALSE);
996 bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE);
998 if (anImageToDump != myLibImage)
1000 FreeImage_Unload (anImageToDump);
1004 #elif defined(HAVE_WINCODEC)
1006 TCollection_AsciiString aFileNameLower = theFileName;
1007 aFileNameLower.LowerCase();
1008 GUID aFileFormat = getNullGuid();
1009 if (aFileNameLower.EndsWith (".ppm"))
1011 return savePPM (theFileName);
1013 else if (aFileNameLower.EndsWith (".bmp"))
1015 aFileFormat = GUID_ContainerFormatBmp;
1017 else if (aFileNameLower.EndsWith (".png"))
1019 aFileFormat = GUID_ContainerFormatPng;
1021 else if (aFileNameLower.EndsWith (".jpg")
1022 || aFileNameLower.EndsWith (".jpeg"))
1024 aFileFormat = GUID_ContainerFormatJpeg;
1026 else if (aFileNameLower.EndsWith (".tiff"))
1028 aFileFormat = GUID_ContainerFormatTiff;
1030 else if (aFileNameLower.EndsWith (".gif"))
1032 aFileFormat = GUID_ContainerFormatGif;
1035 if (aFileFormat == getNullGuid())
1037 Message::DefaultMessenger()->Send ("Error: unsupported image format", Message_Fail);
1041 Image_ComPtr<IWICImagingFactory> aWicImgFactory;
1042 CoInitializeEx (NULL, COINIT_MULTITHREADED);
1043 if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK)
1045 Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail);
1049 Image_ComPtr<IWICStream> aWicFileStream;
1050 Image_ComPtr<IWICBitmapEncoder> aWicEncoder;
1051 const TCollection_ExtendedString aFileNameW (theFileName);
1052 if (aWicImgFactory->CreateStream (&aWicFileStream.ChangePtr()) != S_OK
1053 || aWicFileStream->InitializeFromFilename (aFileNameW.ToWideString(), GENERIC_WRITE) != S_OK)
1055 Message::DefaultMessenger()->Send ("Error: cannot create WIC File Stream", Message_Fail);
1058 if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK
1059 || aWicEncoder->Initialize (aWicFileStream.get(), WICBitmapEncoderNoCache) != S_OK)
1061 Message::DefaultMessenger()->Send ("Error: cannot create WIC Encoder", Message_Fail);
1065 const WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat);
1066 if (aWicPixelFormat == getNullGuid())
1068 Message::DefaultMessenger()->Send ("Error: unsupported pixel format", Message_Fail);
1072 WICPixelFormatGUID aWicPixelFormatRes = aWicPixelFormat;
1073 Image_ComPtr<IWICBitmapFrameEncode> aWicFrameEncode;
1074 if (aWicEncoder->CreateNewFrame (&aWicFrameEncode.ChangePtr(), NULL) != S_OK
1075 || aWicFrameEncode->Initialize (NULL) != S_OK
1076 || aWicFrameEncode->SetSize ((UINT )SizeX(), (UINT )SizeY()) != S_OK
1077 || aWicFrameEncode->SetPixelFormat (&aWicPixelFormatRes) != S_OK)
1079 Message::DefaultMessenger()->Send ("Error: cannot create WIC Frame", Message_Fail);
1083 if (aWicPixelFormatRes != aWicPixelFormat)
1085 Message::DefaultMessenger()->Send ("Error: pixel format is unsupported by image format", Message_Fail);
1091 if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )Data()) != S_OK)
1093 Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail);
1099 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
1101 if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )Row (aRow)) != S_OK)
1103 Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail);
1109 if (aWicFrameEncode->Commit() != S_OK
1110 || aWicEncoder->Commit() != S_OK)
1112 Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC Frame", Message_Fail);
1115 if (aWicFileStream->Commit (STGC_DEFAULT) != S_OK)
1117 //Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC File Stream", Message_Fail);
1122 const Standard_Integer aLen = theFileName.Length();
1123 if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
1124 && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 )
1126 return savePPM (theFileName);
1129 std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n";
1131 return savePPM (theFileName);
1135 // =======================================================================
1136 // function : AdjustGamma
1138 // =======================================================================
1139 bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr)
1141 #ifdef HAVE_FREEIMAGE
1142 return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE;
1144 (void )theGammaCorr;