0030991: Draw Harness - ViewerTest::ParseColor() defines out-of-range alpha component
[occt.git] / src / Image / Image_AlienPixMap.cxx
1 // Created on: 2010-09-16
2 // Created by: KGV
3 // Copyright (c) 2010-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #if !defined(HAVE_FREEIMAGE) && defined(_WIN32)
17   #define HAVE_WINCODEC
18 #endif
19
20 #ifdef HAVE_FREEIMAGE
21   #include <FreeImage.h>
22
23   #ifdef _MSC_VER
24     #pragma comment( lib, "FreeImage.lib" )
25   #endif
26 #elif defined(HAVE_WINCODEC)
27   #include <wincodec.h>
28   // prevent warnings on MSVC10
29   #include <Standard_WarningsDisable.hxx>
30   #include <Standard_TypeDef.hxx>
31   #include <Standard_WarningsRestore.hxx>
32   #undef min
33   #undef max
34
35   #ifdef _MSC_VER
36     #pragma comment(lib, "Ole32.lib")
37   #endif
38 #endif
39
40 #include <Image_AlienPixMap.hxx>
41 #include <gp.hxx>
42 #include <Message.hxx>
43 #include <Message_Messenger.hxx>
44 #include <NCollection_Array1.hxx>
45 #include <Standard_ArrayStreamBuffer.hxx>
46 #include <TCollection_AsciiString.hxx>
47 #include <TCollection_ExtendedString.hxx>
48 #include <OSD_OpenFile.hxx>
49
50 #include <fstream>
51 #include <algorithm>
52
53 IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap,Image_PixMap)
54
55 namespace
56 {
57 #ifdef HAVE_FREEIMAGE
58   static Image_Format convertFromFreeFormat (FREE_IMAGE_TYPE       theFormatFI,
59                                              FREE_IMAGE_COLOR_TYPE theColorTypeFI,
60                                              unsigned              theBitsPerPixel)
61   {
62     switch (theFormatFI)
63     {
64       case FIT_RGBF:   return Image_Format_RGBF;
65       case FIT_RGBAF:  return Image_Format_RGBAF;
66       case FIT_FLOAT:  return Image_Format_GrayF;
67       case FIT_BITMAP:
68       {
69         switch (theColorTypeFI)
70         {
71           case FIC_MINISBLACK:
72           {
73             return Image_Format_Gray;
74           }
75           case FIC_RGB:
76           {
77             if (Image_PixMap::IsBigEndianHost())
78             {
79               return (theBitsPerPixel == 32) ? Image_Format_RGB32 : Image_Format_RGB;
80             }
81             else
82             {
83               return (theBitsPerPixel == 32) ? Image_Format_BGR32 : Image_Format_BGR;
84             }
85           }
86           case FIC_RGBALPHA:
87           {
88             return Image_PixMap::IsBigEndianHost() ? Image_Format_RGBA : Image_Format_BGRA;
89           }
90           default:
91             return Image_Format_UNKNOWN;
92         }
93       }
94       default:
95         return Image_Format_UNKNOWN;
96     }
97   }
98
99   static FREE_IMAGE_TYPE convertToFreeFormat (Image_Format theFormat)
100   {
101     switch (theFormat)
102     {
103       case Image_Format_GrayF:
104       case Image_Format_AlphaF:
105         return FIT_FLOAT;
106       case Image_Format_RGBAF:
107         return FIT_RGBAF;
108       case Image_Format_RGBF:
109         return FIT_RGBF;
110       case Image_Format_RGBA:
111       case Image_Format_BGRA:
112       case Image_Format_RGB32:
113       case Image_Format_BGR32:
114       case Image_Format_RGB:
115       case Image_Format_BGR:
116       case Image_Format_Gray:
117       case Image_Format_Alpha:
118         return FIT_BITMAP;
119       default:
120         return FIT_UNKNOWN;
121     }
122   }
123
124   //! Wrapper for accessing C++ stream from FreeImage.
125   class Image_FreeImageStream
126   {
127   public:
128     //! Construct wrapper over input stream.
129     Image_FreeImageStream (std::istream& theStream)
130     : myIStream (&theStream), myOStream (NULL), myInitPos (theStream.tellg()) {}
131
132     //! Get io object.
133     FreeImageIO GetFiIO() const
134     {
135       FreeImageIO anIo;
136       memset (&anIo, 0, sizeof(anIo));
137       if (myIStream != NULL)
138       {
139         anIo.read_proc = readProc;
140         anIo.seek_proc = seekProc;
141         anIo.tell_proc = tellProc;
142       }
143       if (myOStream != NULL)
144       {
145         anIo.write_proc = writeProc;
146       }
147       return anIo;
148     }
149   public:
150     //! Simulate fread().
151     static unsigned int DLL_CALLCONV readProc (void* theBuffer, unsigned int theSize, unsigned int theCount, fi_handle theHandle)
152     {
153       Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
154       if (aThis->myIStream == NULL)
155       {
156         return 0;
157       }
158
159       if (!aThis->myIStream->read ((char* )theBuffer, std::streamsize(theSize) * std::streamsize(theCount)))
160       {
161         //aThis->myIStream->clear();
162       }
163       const std::streamsize aNbRead = aThis->myIStream->gcount();
164       return (unsigned int )(aNbRead / theSize);
165     }
166
167     //! Simulate fwrite().
168     static unsigned int DLL_CALLCONV writeProc (void* theBuffer, unsigned int theSize, unsigned int theCount, fi_handle theHandle)
169     {
170       Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
171       if (aThis->myOStream != NULL
172        && aThis->myOStream->write ((const char* )theBuffer, std::streamsize(theSize) * std::streamsize(theCount)))
173       {
174         return theCount;
175       }
176       return 0;
177     }
178
179     //! Simulate fseek().
180     static int DLL_CALLCONV seekProc (fi_handle theHandle, long theOffset, int theOrigin)
181     {
182       Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
183       if (aThis->myIStream == NULL)
184       {
185         return -1;
186       }
187
188       bool isSeekDone = false;
189       switch (theOrigin)
190       {
191         case SEEK_SET:
192           if (aThis->myIStream->seekg ((std::streamoff )aThis->myInitPos + theOffset, std::ios::beg))
193           {
194             isSeekDone = true;
195           }
196           break;
197         case SEEK_CUR:
198           if (aThis->myIStream->seekg (theOffset, std::ios::cur))
199           {
200             isSeekDone = true;
201           }
202           break;
203         case SEEK_END:
204           if (aThis->myIStream->seekg (theOffset, std::ios::end))
205           {
206             isSeekDone = true;
207           }
208           break;
209       }
210       return isSeekDone ? 0 : -1;
211     }
212
213     //! Simulate ftell().
214     static long DLL_CALLCONV tellProc (fi_handle theHandle)
215     {
216       Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
217       const long aPos = aThis->myIStream != NULL ? (long )(aThis->myIStream->tellg() - aThis->myInitPos) : 0;
218       return aPos;
219     }
220   private:
221     std::istream*  myIStream;
222     std::ostream*  myOStream;
223     std::streampos myInitPos;
224   };
225
226 #elif defined(HAVE_WINCODEC)
227
228   //! Return a zero GUID
229   static GUID getNullGuid()
230   {
231     GUID aGuid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } };
232     return aGuid;
233   }
234
235   //! Sentry over IUnknown pointer.
236   template<class T> class Image_ComPtr
237   {
238   public:
239     //! Empty constructor.
240     Image_ComPtr()
241     : myPtr (NULL) {}
242
243     //! Destructor.
244     ~Image_ComPtr()
245     {
246       Nullify();
247     }
248
249     //! Return TRUE if pointer is NULL.
250     bool IsNull() const { return myPtr == NULL; }
251
252     //! Release the pointer.
253     void Nullify()
254     {
255       if (myPtr != NULL)
256       {
257         myPtr->Release();
258         myPtr = NULL;
259       }
260     }
261
262     //! Return pointer for initialization.
263     T*& ChangePtr()
264     {
265       Standard_ASSERT_RAISE (myPtr == NULL, "Pointer cannot be initialized twice!");
266       return myPtr;
267     }
268
269     //! Return pointer.
270     T* get() { return myPtr; }
271
272     //! Return pointer.
273     T* operator->() { return get(); }
274
275     //! Cast handle to contained type
276     T& operator*() { return *get(); }
277
278   private:
279     T* myPtr;
280   };
281
282   //! Convert WIC GUID to Image_Format.
283   static Image_Format convertFromWicFormat (const WICPixelFormatGUID& theFormat)
284   {
285     if (theFormat == GUID_WICPixelFormat32bppBGRA)
286     {
287       return Image_Format_BGRA;
288     }
289     else if (theFormat == GUID_WICPixelFormat32bppBGR)
290     {
291       return Image_Format_BGR32;
292     }
293     else if (theFormat == GUID_WICPixelFormat24bppRGB)
294     {
295       return Image_Format_RGB;
296     }
297     else if (theFormat == GUID_WICPixelFormat24bppBGR)
298     {
299       return Image_Format_BGR;
300     }
301     else if (theFormat == GUID_WICPixelFormat8bppGray)
302     {
303       return Image_Format_Gray;
304     }
305     return Image_Format_UNKNOWN;
306   }
307
308   //! Convert Image_Format to WIC GUID.
309   static WICPixelFormatGUID convertToWicFormat (Image_Format theFormat)
310   {
311     switch (theFormat)
312     {
313       case Image_Format_BGRA:   return GUID_WICPixelFormat32bppBGRA;
314       case Image_Format_BGR32:  return GUID_WICPixelFormat32bppBGR;
315       case Image_Format_RGB:    return GUID_WICPixelFormat24bppRGB;
316       case Image_Format_BGR:    return GUID_WICPixelFormat24bppBGR;
317       case Image_Format_Gray:   return GUID_WICPixelFormat8bppGray;
318       case Image_Format_Alpha:  return GUID_WICPixelFormat8bppGray; // GUID_WICPixelFormat8bppAlpha
319       case Image_Format_GrayF:  // GUID_WICPixelFormat32bppGrayFloat
320       case Image_Format_AlphaF:
321       case Image_Format_RGBAF:  // GUID_WICPixelFormat128bppRGBAFloat
322       case Image_Format_RGBF:   // GUID_WICPixelFormat96bppRGBFloat
323       case Image_Format_RGBA:   // GUID_WICPixelFormat32bppRGBA
324       case Image_Format_RGB32:  // GUID_WICPixelFormat32bppRGB
325       default:
326         return getNullGuid();
327     }
328   }
329
330 #endif
331 }
332
333 // =======================================================================
334 // function : Image_AlienPixMap
335 // purpose  :
336 // =======================================================================
337 Image_AlienPixMap::Image_AlienPixMap()
338 : myLibImage (NULL)
339 {
340   SetTopDown (false);
341 }
342
343 // =======================================================================
344 // function : ~Image_AlienPixMap
345 // purpose  :
346 // =======================================================================
347 Image_AlienPixMap::~Image_AlienPixMap()
348 {
349   Clear();
350 }
351
352 // =======================================================================
353 // function : InitWrapper
354 // purpose  :
355 // =======================================================================
356 bool Image_AlienPixMap::InitWrapper (Image_Format,
357                                      Standard_Byte*,
358                                      const Standard_Size,
359                                      const Standard_Size,
360                                      const Standard_Size)
361 {
362   Clear();
363   return false;
364 }
365
366 // =======================================================================
367 // function : InitTrash
368 // purpose  :
369 // =======================================================================
370 #ifdef HAVE_FREEIMAGE
371 bool Image_AlienPixMap::InitTrash (Image_Format        thePixelFormat,
372                                    const Standard_Size theSizeX,
373                                    const Standard_Size theSizeY,
374                                    const Standard_Size /*theSizeRowBytes*/)
375 {
376   Clear();
377   FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat);
378   int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8;
379   if (aFormatFI == FIT_UNKNOWN)
380   {
381     aFormatFI     = FIT_BITMAP;
382     aBitsPerPixel = 24;
383   }
384
385   FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel);
386   Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
387                                                 FreeImage_GetColorType(anImage),
388                                                 FreeImage_GetBPP      (anImage));
389   if (thePixelFormat == Image_Format_BGR32
390    || thePixelFormat == Image_Format_RGB32)
391   {
392     //FreeImage_SetTransparent (anImage, FALSE);
393     aFormat = (aFormat == Image_Format_BGRA) ? Image_Format_BGR32 : Image_Format_RGB32;
394   }
395
396   Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
397                              FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
398   SetTopDown (false);
399
400   // assign image after wrapper initialization (virtual Clear() called inside)
401   myLibImage = anImage;
402   return true;
403 }
404 #elif defined(HAVE_WINCODEC)
405 bool Image_AlienPixMap::InitTrash (Image_Format        thePixelFormat,
406                                    const Standard_Size theSizeX,
407                                    const Standard_Size theSizeY,
408                                    const Standard_Size theSizeRowBytes)
409 {
410   Clear();
411   Image_Format aFormat = thePixelFormat;
412   switch (aFormat)
413   {
414     case Image_Format_RGB:
415       aFormat = Image_Format_BGR;
416       break;
417     case Image_Format_RGB32:
418       aFormat = Image_Format_BGR32;
419       break;
420     case Image_Format_RGBA:
421       aFormat = Image_Format_BGRA;
422       break;
423     default:
424       break;
425   }
426
427   if (!Image_PixMap::InitTrash (aFormat, theSizeX, theSizeY, theSizeRowBytes))
428   {
429     return false;
430   }
431   SetTopDown (true);
432   return true;
433 }
434 #else
435 bool Image_AlienPixMap::InitTrash (Image_Format        thePixelFormat,
436                                    const Standard_Size theSizeX,
437                                    const Standard_Size theSizeY,
438                                    const Standard_Size theSizeRowBytes)
439 {
440   return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes);
441 }
442 #endif
443
444 // =======================================================================
445 // function : InitCopy
446 // purpose  :
447 // =======================================================================
448 bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy)
449 {
450   if (&theCopy == this)
451   {
452     // self-copying disallowed
453     return false;
454   }
455   if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes()))
456   {
457     return false;
458   }
459
460   if (myImgFormat == theCopy.Format())
461   {
462     if (SizeRowBytes() == theCopy.SizeRowBytes()
463      && TopDownInc()   == theCopy.TopDownInc())
464     {
465       // copy with one call
466       memcpy (ChangeData(), theCopy.Data(), std::min (SizeBytes(), theCopy.SizeBytes()));
467       return true;
468     }
469
470     // copy row-by-row
471     const Standard_Size aRowSizeBytes = std::min (SizeRowBytes(), theCopy.SizeRowBytes());
472     for (Standard_Size aRow = 0; aRow < myData.SizeY; ++aRow)
473     {
474       memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes);
475     }
476     return true;
477   }
478
479   // pixel format conversion required
480   Clear();
481   return false;
482 }
483
484 // =======================================================================
485 // function : Clear
486 // purpose  :
487 // =======================================================================
488 void Image_AlienPixMap::Clear()
489 {
490   Image_PixMap::Clear();
491 #ifdef HAVE_FREEIMAGE
492   if (myLibImage != NULL)
493   {
494     FreeImage_Unload (myLibImage);
495     myLibImage = NULL;
496   }
497 #endif
498 }
499
500 // =======================================================================
501 // function : IsTopDownDefault
502 // purpose  :
503 // =======================================================================
504 bool Image_AlienPixMap::IsTopDownDefault()
505 {
506 #ifdef HAVE_FREEIMAGE
507   return false;
508 #elif defined(HAVE_WINCODEC)
509   return true;
510 #else
511   return false;
512 #endif
513 }
514
515 // =======================================================================
516 // function : Load
517 // purpose  :
518 // =======================================================================
519 #ifdef HAVE_FREEIMAGE
520 bool Image_AlienPixMap::Load (const Standard_Byte* theData,
521                               Standard_Size theLength,
522                               const TCollection_AsciiString& theImagePath)
523 {
524   Clear();
525
526 #ifdef _WIN32
527   const TCollection_ExtendedString aFileNameW (theImagePath);
528 #endif
529   FREE_IMAGE_FORMAT aFIF = FIF_UNKNOWN;
530   FIMEMORY* aFiMem = NULL;
531   if (theData != NULL)
532   {
533     aFiMem = FreeImage_OpenMemory ((BYTE* )theData, (DWORD )theLength);
534     aFIF = FreeImage_GetFileTypeFromMemory (aFiMem, 0);
535   }
536   else
537   {
538   #ifdef _WIN32
539     aFIF = FreeImage_GetFileTypeU (aFileNameW.ToWideString(), 0);
540   #else
541     aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0);
542   #endif
543   }
544   if (aFIF == FIF_UNKNOWN)
545   {
546     // no signature? try to guess the file format from the file extension
547     aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString());
548   }
549   if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
550   {
551     ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported file format.",
552                                          Message_Fail);
553     if (aFiMem != NULL)
554     {
555       FreeImage_CloseMemory (aFiMem);
556     }
557     return false;
558   }
559
560   int aLoadFlags = 0;
561   if (aFIF == FIF_GIF)
562   {
563     // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
564     aLoadFlags = GIF_PLAYBACK;
565   }
566   else if (aFIF == FIF_ICO)
567   {
568     // convert to 32bpp and create an alpha channel from the AND-mask when loading
569     aLoadFlags = ICO_MAKEALPHA;
570   }
571
572   FIBITMAP* anImage = NULL;
573   if (theData != NULL)
574   {
575     anImage = FreeImage_LoadFromMemory (aFIF, aFiMem, aLoadFlags);
576     FreeImage_CloseMemory (aFiMem);
577     aFiMem = NULL;
578   }
579   else
580   {
581   #ifdef _WIN32
582     anImage = FreeImage_LoadU (aFIF, aFileNameW.ToWideString(), aLoadFlags);
583   #else
584     anImage = FreeImage_Load  (aFIF, theImagePath.ToCString(), aLoadFlags);
585   #endif
586   }
587   if (anImage == NULL)
588   {
589     TCollection_AsciiString aMessage = "Error: image file '";
590     aMessage.AssignCat (theImagePath);
591     aMessage.AssignCat ("' is missing or invalid.");
592     ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
593     return false;
594   }
595
596   if (FreeImage_GetBPP (anImage) == 1)
597   {
598     FIBITMAP* aTmpImage = FreeImage_ConvertTo8Bits (anImage);
599     FreeImage_Unload (anImage);
600     anImage = aTmpImage;
601   }
602
603   Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
604                                                 FreeImage_GetColorType(anImage),
605                                                 FreeImage_GetBPP      (anImage));
606   if (aFormat == Image_Format_UNKNOWN)
607   {
608     //anImage = FreeImage_ConvertTo24Bits (anImage);
609     ::Message::DefaultMessenger()->Send (    TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported pixel format.",
610                                          Message_Fail);
611     return false;
612   }
613
614   Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
615                              FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
616   SetTopDown (false);
617
618   // assign image after wrapper initialization (virtual Clear() called inside)
619   myLibImage = anImage;
620   return true;
621 }
622
623 bool Image_AlienPixMap::Load (std::istream& theStream,
624                               const TCollection_AsciiString& theFileName)
625 {
626   Clear();
627
628   Image_FreeImageStream aStream (theStream);
629   FreeImageIO aFiIO = aStream.GetFiIO();
630
631   FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeFromHandle (&aFiIO, &aStream, 0);
632   if (aFIF == FIF_UNKNOWN)
633   {
634     // no signature? try to guess the file format from the file extension
635     aFIF = FreeImage_GetFIFFromFilename (theFileName.ToCString());
636   }
637   if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
638   {
639     ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported file format.",
640                                          Message_Fail);
641     return false;
642   }
643
644   int aLoadFlags = 0;
645   if (aFIF == FIF_GIF)
646   {
647     // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
648     aLoadFlags = GIF_PLAYBACK;
649   }
650   else if (aFIF == FIF_ICO)
651   {
652     // convert to 32bpp and create an alpha channel from the AND-mask when loading
653     aLoadFlags = ICO_MAKEALPHA;
654   }
655
656   FIBITMAP* anImage = FreeImage_LoadFromHandle (aFIF, &aFiIO, &aStream, aLoadFlags);
657   if (anImage == NULL)
658   {
659     ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' is missing or invalid.",
660                                          Message_Fail);
661     return false;
662   }
663
664   Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
665                                                 FreeImage_GetColorType(anImage),
666                                                 FreeImage_GetBPP      (anImage));
667   if (aFormat == Image_Format_UNKNOWN)
668   {
669     ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported pixel format.",
670                                          Message_Fail);
671     return false;
672   }
673
674   Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
675                              FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
676   SetTopDown (false);
677
678   // assign image after wrapper initialization (virtual Clear() called inside)
679   myLibImage = anImage;
680   return true;
681 }
682
683 #elif defined(HAVE_WINCODEC)
684 bool Image_AlienPixMap::Load (const Standard_Byte* theData,
685                               Standard_Size theLength,
686                               const TCollection_AsciiString& theFileName)
687 {
688   Clear();
689
690   Image_ComPtr<IWICImagingFactory> aWicImgFactory;
691   CoInitializeEx (NULL, COINIT_MULTITHREADED);
692   if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK)
693   {
694     Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail);
695     return false;
696   }
697
698   Image_ComPtr<IWICBitmapDecoder> aWicDecoder;
699   Image_ComPtr<IWICStream> aWicStream;
700   if (theData != NULL)
701   {
702     if (aWicImgFactory->CreateStream (&aWicStream.ChangePtr()) != S_OK
703      || aWicStream->InitializeFromMemory ((BYTE* )theData, (DWORD )theLength) != S_OK)
704     {
705       Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Stream", Message_Fail);
706       return false;
707     }
708     if (aWicImgFactory->CreateDecoderFromStream (aWicStream.get(), NULL, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK)
709     {
710       Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail);
711       return false;
712     }
713   }
714   else
715   {
716     const TCollection_ExtendedString aFileNameW (theFileName);
717     if (aWicImgFactory->CreateDecoderFromFilename (aFileNameW.ToWideString(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK)
718     {
719       Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail);
720       return false;
721     }
722   }
723
724   UINT aFrameCount = 0, aFrameSizeX = 0, aFrameSizeY = 0;
725   WICPixelFormatGUID aWicPixelFormat = getNullGuid();
726   Image_ComPtr<IWICBitmapFrameDecode> aWicFrameDecode;
727   if (aWicDecoder->GetFrameCount (&aFrameCount) != S_OK
728    || aFrameCount < 1
729    || aWicDecoder->GetFrame (0, &aWicFrameDecode.ChangePtr()) != S_OK
730    || aWicFrameDecode->GetSize (&aFrameSizeX, &aFrameSizeY) != S_OK
731    || aWicFrameDecode->GetPixelFormat (&aWicPixelFormat))
732   {
733     Message::DefaultMessenger()->Send ("Error: cannot get WIC Image Frame", Message_Fail);
734     return false;
735   }
736
737   Image_ComPtr<IWICFormatConverter> aWicConvertedFrame;
738   Image_Format aPixelFormat = convertFromWicFormat (aWicPixelFormat);
739   if (aPixelFormat == Image_Format_UNKNOWN)
740   {
741     aPixelFormat = Image_Format_RGB;
742     if (aWicImgFactory->CreateFormatConverter (&aWicConvertedFrame.ChangePtr()) != S_OK
743      || aWicConvertedFrame->Initialize (aWicFrameDecode.get(), convertToWicFormat (aPixelFormat), WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom) != S_OK)
744     {
745       Message::DefaultMessenger()->Send ("Error: cannot convert WIC Image Frame to RGB format", Message_Fail);
746       return false;
747     }
748     aWicFrameDecode.Nullify();
749   }
750
751   if (!Image_PixMap::InitTrash (aPixelFormat, aFrameSizeX, aFrameSizeY))
752   {
753     Message::DefaultMessenger()->Send ("Error: cannot initialize memory for image", Message_Fail);
754     return false;
755   }
756
757   IWICBitmapSource* aWicSrc = aWicFrameDecode.get();
758   if(!aWicConvertedFrame.IsNull())
759   {
760     aWicSrc = aWicConvertedFrame.get();
761   }
762   if (aWicSrc->CopyPixels (NULL, (UINT )SizeRowBytes(), (UINT )SizeBytes(), ChangeData()) != S_OK)
763   {
764     Message::DefaultMessenger()->Send ("Error: cannot copy pixels from WIC Image", Message_Fail);
765     return false;
766   }
767   SetTopDown (true);
768   return true;
769 }
770 bool Image_AlienPixMap::Load (std::istream& theStream,
771                               const TCollection_AsciiString& theFilePath)
772 {
773   Clear();
774
775   // fallback copying stream data into transient buffer
776   const std::streamoff aStart = theStream.tellg();
777   theStream.seekg (0, std::ios::end);
778   const Standard_Integer aLen = Standard_Integer(theStream.tellg() - aStart);
779   theStream.seekg (aStart);
780   if (aLen <= 0)
781   {
782     Message::DefaultMessenger()->Send ("Error: empty stream", Message_Fail);
783     return false;
784   }
785
786   NCollection_Array1<Standard_Byte> aBuff (1, aLen);
787   if (!theStream.read ((char* )&aBuff.ChangeFirst(), aBuff.Size()))
788   {
789     Message::DefaultMessenger()->Send ("Error: unable to read stream", Message_Fail);
790     return false;
791   }
792
793   return Load (&aBuff.ChangeFirst(), aBuff.Size(), theFilePath);
794 }
795 #else
796 bool Image_AlienPixMap::Load (std::istream& ,
797                               const TCollection_AsciiString& )
798 {
799   Clear();
800   Message::DefaultMessenger()->Send ("Error: no image library available", Message_Fail);
801   return false;
802 }
803 bool Image_AlienPixMap::Load (const Standard_Byte* ,
804                               Standard_Size ,
805                               const TCollection_AsciiString& )
806 {
807   Clear();
808   Message::DefaultMessenger()->Send ("Error: no image library available", Message_Fail);
809   return false;
810 }
811 #endif
812
813 // =======================================================================
814 // function : savePPM
815 // purpose  :
816 // =======================================================================
817 bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const
818 {
819   if (IsEmpty())
820   {
821     return false;
822   }
823
824   // Open file
825   FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb");
826   if (aFile == NULL)
827   {
828     return false;
829   }
830
831   // Write header
832   fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY());
833   fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n");
834
835   // Write pixel data
836   Standard_Byte aByte;
837   for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
838   {
839     for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
840     {
841       // extremely SLOW but universal (implemented for all supported pixel formats)
842       const Quantity_ColorRGBA aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow);
843       aByte = Standard_Byte(aColor.GetRGB().Red()   * 255.0); fwrite (&aByte, 1, 1, aFile);
844       aByte = Standard_Byte(aColor.GetRGB().Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
845       aByte = Standard_Byte(aColor.GetRGB().Blue()  * 255.0); fwrite (&aByte, 1, 1, aFile);
846     }
847   }
848
849   // Close file
850   fclose (aFile);
851   return true;
852 }
853
854 // =======================================================================
855 // function : Save
856 // purpose  :
857 // =======================================================================
858 bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName)
859 {
860 #ifdef HAVE_FREEIMAGE
861   if (myLibImage == NULL)
862   {
863     return false;
864   }
865
866 #ifdef _WIN32
867   const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True);
868   FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU (aFileNameW.ToWideString());
869 #else
870   FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString());
871 #endif
872   if (anImageFormat == FIF_UNKNOWN)
873   {
874 #ifdef OCCT_DEBUG
875     std::cerr << "Image_PixMap, image format doesn't supported!\n";
876 #endif
877     return false;
878   }
879
880   if (IsTopDown())
881   {
882     FreeImage_FlipVertical (myLibImage);
883     SetTopDown (false);
884   }
885
886   // FreeImage doesn't provide flexible format conversion API
887   // so we should perform multiple conversions in some cases!
888   FIBITMAP* anImageToDump = myLibImage;
889   switch (anImageFormat)
890   {
891     case FIF_PNG:
892     case FIF_BMP:
893     {
894       if (Format() == Image_Format_BGR32
895        || Format() == Image_Format_RGB32)
896       {
897         // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
898         for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
899         {
900           for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
901           {
902             myData.ChangeValue (aRow, aCol)[3] = 0xFF;
903           }
904         }
905       }
906       else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
907       {
908         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
909       }
910       break;
911     }
912     case FIF_GIF:
913     {
914       FIBITMAP* aTmpBitmap = myLibImage;
915       if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
916       {
917         aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
918         if (aTmpBitmap == NULL)
919         {
920           return false;
921         }
922       }
923
924       if (FreeImage_GetBPP (aTmpBitmap) != 24)
925       {
926         FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
927         if (aTmpBitmap != myLibImage)
928         {
929           FreeImage_Unload (aTmpBitmap);
930         }
931         if (aTmpBitmap24 == NULL)
932         {
933           return false;
934         }
935         aTmpBitmap = aTmpBitmap24;
936       }
937
938       // need conversion to image with palette (requires 24bit bitmap)
939       anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
940       if (aTmpBitmap != myLibImage)
941       {
942         FreeImage_Unload (aTmpBitmap);
943       }
944       break;
945     }
946     case FIF_HDR:
947     case FIF_EXR:
948     {
949       if (Format() == Image_Format_Gray
950        || Format() == Image_Format_Alpha)
951       {
952         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
953       }
954       else if (Format() == Image_Format_RGBA
955             || Format() == Image_Format_BGRA)
956       {
957         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
958       }
959       else
960       {
961         FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
962         if (aImgTypeFI != FIT_RGBF
963          && aImgTypeFI != FIT_RGBAF
964          && aImgTypeFI != FIT_FLOAT)
965         {
966           anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
967         }
968       }
969       break;
970     }
971     default:
972     {
973       if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
974       {
975         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
976         if (anImageToDump == NULL)
977         {
978           return false;
979         }
980       }
981
982       if (FreeImage_GetBPP (anImageToDump) != 24)
983       {
984         FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
985         if (anImageToDump != myLibImage)
986         {
987           FreeImage_Unload (anImageToDump);
988         }
989         if (aTmpBitmap24 == NULL)
990         {
991           return false;
992         }
993         anImageToDump = aTmpBitmap24;
994       }
995       break;
996     }
997   }
998
999   if (anImageToDump == NULL)
1000   {
1001     return false;
1002   }
1003
1004 #ifdef _WIN32
1005   bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString()) != FALSE);
1006 #else
1007   bool isSaved = (FreeImage_Save  (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE);
1008 #endif
1009   if (anImageToDump != myLibImage)
1010   {
1011     FreeImage_Unload (anImageToDump);
1012   }
1013   return isSaved;
1014
1015 #elif defined(HAVE_WINCODEC)
1016
1017   TCollection_AsciiString aFileNameLower = theFileName;
1018   aFileNameLower.LowerCase();
1019   GUID aFileFormat = getNullGuid();
1020   if (aFileNameLower.EndsWith (".ppm"))
1021   {
1022     return savePPM (theFileName);
1023   }
1024   else if (aFileNameLower.EndsWith (".bmp"))
1025   {
1026     aFileFormat = GUID_ContainerFormatBmp;
1027   }
1028   else if (aFileNameLower.EndsWith (".png"))
1029   {
1030     aFileFormat = GUID_ContainerFormatPng;
1031   }
1032   else if (aFileNameLower.EndsWith (".jpg")
1033         || aFileNameLower.EndsWith (".jpeg"))
1034   {
1035     aFileFormat = GUID_ContainerFormatJpeg;
1036   }
1037   else if (aFileNameLower.EndsWith (".tiff"))
1038   {
1039     aFileFormat = GUID_ContainerFormatTiff;
1040   }
1041   else if (aFileNameLower.EndsWith (".gif"))
1042   {
1043     aFileFormat = GUID_ContainerFormatGif;
1044   }
1045
1046   if (aFileFormat == getNullGuid())
1047   {
1048     Message::DefaultMessenger()->Send ("Error: unsupported image format", Message_Fail);
1049     return false;
1050   }
1051
1052   Image_ComPtr<IWICImagingFactory> aWicImgFactory;
1053   CoInitializeEx (NULL, COINIT_MULTITHREADED);
1054   if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK)
1055   {
1056     Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail);
1057     return false;
1058   }
1059
1060   Image_ComPtr<IWICStream> aWicFileStream;
1061   Image_ComPtr<IWICBitmapEncoder> aWicEncoder;
1062   const TCollection_ExtendedString aFileNameW (theFileName);
1063   if (aWicImgFactory->CreateStream (&aWicFileStream.ChangePtr()) != S_OK
1064    || aWicFileStream->InitializeFromFilename (aFileNameW.ToWideString(), GENERIC_WRITE) != S_OK)
1065   {
1066     Message::DefaultMessenger()->Send ("Error: cannot create WIC File Stream", Message_Fail);
1067     return false;
1068   }
1069   if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK
1070    || aWicEncoder->Initialize (aWicFileStream.get(), WICBitmapEncoderNoCache) != S_OK)
1071   {
1072     Message::DefaultMessenger()->Send ("Error: cannot create WIC Encoder", Message_Fail);
1073     return false;
1074   }
1075
1076   const WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat);
1077   if (aWicPixelFormat == getNullGuid())
1078   {
1079     Message::DefaultMessenger()->Send ("Error: unsupported pixel format", Message_Fail);
1080     return false;
1081   }
1082
1083   WICPixelFormatGUID aWicPixelFormatRes = aWicPixelFormat;
1084   Image_ComPtr<IWICBitmapFrameEncode> aWicFrameEncode;
1085   if (aWicEncoder->CreateNewFrame (&aWicFrameEncode.ChangePtr(), NULL) != S_OK
1086    || aWicFrameEncode->Initialize (NULL) != S_OK
1087    || aWicFrameEncode->SetSize ((UINT )SizeX(), (UINT )SizeY()) != S_OK
1088    || aWicFrameEncode->SetPixelFormat (&aWicPixelFormatRes) != S_OK)
1089   {
1090     Message::DefaultMessenger()->Send ("Error: cannot create WIC Frame", Message_Fail);
1091     return false;
1092   }
1093
1094   if (aWicPixelFormatRes != aWicPixelFormat)
1095   {
1096     Message::DefaultMessenger()->Send ("Error: pixel format is unsupported by image format", Message_Fail);
1097     return false;
1098   }
1099
1100   if (IsTopDown())
1101   {
1102     if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )Data()) != S_OK)
1103     {
1104       Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail);
1105       return false;
1106     }
1107   }
1108   else
1109   {
1110     for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
1111     {
1112       if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )Row (aRow)) != S_OK)
1113       {
1114         Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail);
1115         return false;
1116       }
1117     }
1118   }
1119
1120   if (aWicFrameEncode->Commit() != S_OK
1121    || aWicEncoder->Commit() != S_OK)
1122   {
1123     Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC Frame", Message_Fail);
1124     return false;
1125   }
1126   if (aWicFileStream->Commit (STGC_DEFAULT) != S_OK)
1127   {
1128     //Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC File Stream", Message_Fail);
1129     //return false;
1130   }
1131   return true;
1132 #else
1133   const Standard_Integer aLen = theFileName.Length();
1134   if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
1135       && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 )
1136   {
1137     return savePPM (theFileName);
1138   }
1139 #ifdef OCCT_DEBUG
1140   std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n";
1141 #endif
1142   return savePPM (theFileName);
1143 #endif
1144 }
1145
1146 // =======================================================================
1147 // function : AdjustGamma
1148 // purpose  :
1149 // =======================================================================
1150 bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr)
1151 {
1152 #ifdef HAVE_FREEIMAGE
1153   return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE;
1154 #else
1155   (void )theGammaCorr;
1156   return false;
1157 #endif
1158 }