0029055: Visualization, Image_AlienPixMap - fallback using Wincodec
[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 <initguid.h>
28   #include <wincodec.h>
29   #undef min
30   #undef max
31 #endif
32
33 #include <Image_AlienPixMap.hxx>
34 #include <gp.hxx>
35 #include <Message.hxx>
36 #include <Message_Messenger.hxx>
37 #include <TCollection_AsciiString.hxx>
38 #include <TCollection_ExtendedString.hxx>
39 #include <OSD_OpenFile.hxx>
40 #include <fstream>
41 #include <algorithm>
42
43 IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap,Image_PixMap)
44
45 namespace
46 {
47 #ifdef HAVE_FREEIMAGE
48   static Image_Format convertFromFreeFormat (FREE_IMAGE_TYPE       theFormatFI,
49                                              FREE_IMAGE_COLOR_TYPE theColorTypeFI,
50                                              unsigned              theBitsPerPixel)
51   {
52     switch (theFormatFI)
53     {
54       case FIT_RGBF:   return Image_Format_RGBF;
55       case FIT_RGBAF:  return Image_Format_RGBAF;
56       case FIT_FLOAT:  return Image_Format_GrayF;
57       case FIT_BITMAP:
58       {
59         switch (theColorTypeFI)
60         {
61           case FIC_MINISBLACK:
62           {
63             return Image_Format_Gray;
64           }
65           case FIC_RGB:
66           {
67             if (Image_PixMap::IsBigEndianHost())
68             {
69               return (theBitsPerPixel == 32) ? Image_Format_RGB32 : Image_Format_RGB;
70             }
71             else
72             {
73               return (theBitsPerPixel == 32) ? Image_Format_BGR32 : Image_Format_BGR;
74             }
75           }
76           case FIC_RGBALPHA:
77           {
78             return Image_PixMap::IsBigEndianHost() ? Image_Format_RGBA : Image_Format_BGRA;
79           }
80           default:
81             return Image_Format_UNKNOWN;
82         }
83       }
84       default:
85         return Image_Format_UNKNOWN;
86     }
87   }
88
89   static FREE_IMAGE_TYPE convertToFreeFormat (Image_Format theFormat)
90   {
91     switch (theFormat)
92     {
93       case Image_Format_GrayF:
94       case Image_Format_AlphaF:
95         return FIT_FLOAT;
96       case Image_Format_RGBAF:
97         return FIT_RGBAF;
98       case Image_Format_RGBF:
99         return FIT_RGBF;
100       case Image_Format_RGBA:
101       case Image_Format_BGRA:
102       case Image_Format_RGB32:
103       case Image_Format_BGR32:
104       case Image_Format_RGB:
105       case Image_Format_BGR:
106       case Image_Format_Gray:
107       case Image_Format_Alpha:
108         return FIT_BITMAP;
109       default:
110         return FIT_UNKNOWN;
111     }
112   }
113 #elif defined(HAVE_WINCODEC)
114
115   //! Return a zero GUID
116   static GUID getNullGuid()
117   {
118     GUID aGuid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } };
119     return aGuid;
120   }
121
122   //! Sentry over IUnknown pointer.
123   template<class T> class Image_ComPtr
124   {
125   public:
126     //! Empty constructor.
127     Image_ComPtr()
128     : myPtr (NULL) {}
129
130     //! Destructor.
131     ~Image_ComPtr()
132     {
133       Nullify();
134     }
135
136     //! Return TRUE if pointer is NULL.
137     bool IsNull() const { return myPtr == NULL; }
138
139     //! Release the pointer.
140     void Nullify()
141     {
142       if (myPtr != NULL)
143       {
144         myPtr->Release();
145         myPtr = NULL;
146       }
147     }
148
149     //! Return pointer for initialization.
150     T*& ChangePtr()
151     {
152       Standard_ASSERT_RAISE (myPtr == NULL, "Pointer cannot be initialized twice!");
153       return myPtr;
154     }
155
156     //! Return pointer.
157     T* get() { return myPtr; }
158
159     //! Return pointer.
160     T* operator->() { return get(); }
161
162     //! Cast handle to contained type
163     T& operator*() { return *get(); }
164
165   private:
166     T* myPtr;
167   };
168
169   //! Convert WIC GUID to Image_Format.
170   static Image_Format convertFromWicFormat (const WICPixelFormatGUID& theFormat)
171   {
172     if (theFormat == GUID_WICPixelFormat32bppBGRA)
173     {
174       return Image_Format_BGRA;
175     }
176     else if (theFormat == GUID_WICPixelFormat32bppBGR)
177     {
178       return Image_Format_BGR32;
179     }
180     else if (theFormat == GUID_WICPixelFormat24bppRGB)
181     {
182       return Image_Format_RGB;
183     }
184     else if (theFormat == GUID_WICPixelFormat24bppBGR)
185     {
186       return Image_Format_BGR;
187     }
188     else if (theFormat == GUID_WICPixelFormat8bppGray)
189     {
190       return Image_Format_Gray;
191     }
192     return Image_Format_UNKNOWN;
193   }
194
195   //! Convert Image_Format to WIC GUID.
196   static WICPixelFormatGUID convertToWicFormat (Image_Format theFormat)
197   {
198     switch (theFormat)
199     {
200       case Image_Format_BGRA:   return GUID_WICPixelFormat32bppBGRA;
201       case Image_Format_BGR32:  return GUID_WICPixelFormat32bppBGR;
202       case Image_Format_RGB:    return GUID_WICPixelFormat24bppRGB;
203       case Image_Format_BGR:    return GUID_WICPixelFormat24bppBGR;
204       case Image_Format_Gray:   return GUID_WICPixelFormat8bppGray;
205       case Image_Format_Alpha:  return GUID_WICPixelFormat8bppGray; // GUID_WICPixelFormat8bppAlpha
206       case Image_Format_GrayF:  // GUID_WICPixelFormat32bppGrayFloat
207       case Image_Format_AlphaF:
208       case Image_Format_RGBAF:  // GUID_WICPixelFormat128bppRGBAFloat
209       case Image_Format_RGBF:   // GUID_WICPixelFormat96bppRGBFloat
210       case Image_Format_RGBA:   // GUID_WICPixelFormat32bppRGBA
211       case Image_Format_RGB32:  // GUID_WICPixelFormat32bppRGB
212       default:
213         return getNullGuid();
214     }
215   }
216
217 #endif
218 }
219
220 // =======================================================================
221 // function : Image_AlienPixMap
222 // purpose  :
223 // =======================================================================
224 Image_AlienPixMap::Image_AlienPixMap()
225 : myLibImage (NULL)
226 {
227   SetTopDown (false);
228 }
229
230 // =======================================================================
231 // function : ~Image_AlienPixMap
232 // purpose  :
233 // =======================================================================
234 Image_AlienPixMap::~Image_AlienPixMap()
235 {
236   Clear();
237 }
238
239 // =======================================================================
240 // function : InitWrapper
241 // purpose  :
242 // =======================================================================
243 bool Image_AlienPixMap::InitWrapper (Image_Format,
244                                      Standard_Byte*,
245                                      const Standard_Size,
246                                      const Standard_Size,
247                                      const Standard_Size)
248 {
249   Clear();
250   return false;
251 }
252
253 // =======================================================================
254 // function : InitTrash
255 // purpose  :
256 // =======================================================================
257 #ifdef HAVE_FREEIMAGE
258 bool Image_AlienPixMap::InitTrash (Image_Format        thePixelFormat,
259                                    const Standard_Size theSizeX,
260                                    const Standard_Size theSizeY,
261                                    const Standard_Size /*theSizeRowBytes*/)
262 {
263   Clear();
264   FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat);
265   int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8;
266   if (aFormatFI == FIT_UNKNOWN)
267   {
268     aFormatFI     = FIT_BITMAP;
269     aBitsPerPixel = 24;
270   }
271
272   FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel);
273   Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
274                                                 FreeImage_GetColorType(anImage),
275                                                 FreeImage_GetBPP      (anImage));
276   if (thePixelFormat == Image_Format_BGR32
277    || thePixelFormat == Image_Format_RGB32)
278   {
279     //FreeImage_SetTransparent (anImage, FALSE);
280     aFormat = (aFormat == Image_Format_BGRA) ? Image_Format_BGR32 : Image_Format_RGB32;
281   }
282
283   Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
284                              FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
285   SetTopDown (false);
286
287   // assign image after wrapper initialization (virtual Clear() called inside)
288   myLibImage = anImage;
289   return true;
290 }
291 #elif defined(HAVE_WINCODEC)
292 bool Image_AlienPixMap::InitTrash (Image_Format        thePixelFormat,
293                                    const Standard_Size theSizeX,
294                                    const Standard_Size theSizeY,
295                                    const Standard_Size theSizeRowBytes)
296 {
297   Clear();
298   Image_Format aFormat = thePixelFormat;
299   switch (aFormat)
300   {
301     case Image_Format_RGB:
302       aFormat = Image_Format_BGR;
303       break;
304     case Image_Format_RGB32:
305       aFormat = Image_Format_BGR32;
306       break;
307     case Image_Format_RGBA:
308       aFormat = Image_Format_BGRA;
309       break;
310     default:
311       break;
312   }
313
314   if (!Image_PixMap::InitTrash (aFormat, theSizeX, theSizeY, theSizeRowBytes))
315   {
316     return false;
317   }
318   SetTopDown (true);
319   return true;
320 }
321 #else
322 bool Image_AlienPixMap::InitTrash (Image_Format        thePixelFormat,
323                                    const Standard_Size theSizeX,
324                                    const Standard_Size theSizeY,
325                                    const Standard_Size theSizeRowBytes)
326 {
327   return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes);
328 }
329 #endif
330
331 // =======================================================================
332 // function : InitCopy
333 // purpose  :
334 // =======================================================================
335 bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy)
336 {
337   if (&theCopy == this)
338   {
339     // self-copying disallowed
340     return false;
341   }
342   if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes()))
343   {
344     return false;
345   }
346
347   if (myImgFormat == theCopy.Format())
348   {
349     if (SizeRowBytes() == theCopy.SizeRowBytes()
350      && TopDownInc()   == theCopy.TopDownInc())
351     {
352       // copy with one call
353       memcpy (ChangeData(), theCopy.Data(), std::min (SizeBytes(), theCopy.SizeBytes()));
354       return true;
355     }
356
357     // copy row-by-row
358     const Standard_Size aRowSizeBytes = std::min (SizeRowBytes(), theCopy.SizeRowBytes());
359     for (Standard_Size aRow = 0; aRow < myData.SizeY; ++aRow)
360     {
361       memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes);
362     }
363     return true;
364   }
365
366   // pixel format conversion required
367   Clear();
368   return false;
369 }
370
371 // =======================================================================
372 // function : Clear
373 // purpose  :
374 // =======================================================================
375 void Image_AlienPixMap::Clear()
376 {
377   Image_PixMap::Clear();
378 #ifdef HAVE_FREEIMAGE
379   if (myLibImage != NULL)
380   {
381     FreeImage_Unload (myLibImage);
382     myLibImage = NULL;
383   }
384 #endif
385 }
386
387 // =======================================================================
388 // function : Load
389 // purpose  :
390 // =======================================================================
391 #ifdef HAVE_FREEIMAGE
392 bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath)
393 {
394   Clear();
395
396 #ifdef _WIN32
397   const TCollection_ExtendedString aFileNameW (theImagePath);
398   FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeU (aFileNameW.ToWideString(), 0);
399 #else
400   FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0);
401 #endif
402   if (aFIF == FIF_UNKNOWN)
403   {
404     // no signature? try to guess the file format from the file extension
405     aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString());
406   }
407   if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
408   {
409     TCollection_AsciiString aMessage = "Error: image file '";
410     aMessage.AssignCat (theImagePath);
411     aMessage.AssignCat ("' has unsupported file format.");
412     ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
413     return false;
414   }
415
416   int aLoadFlags = 0;
417   if (aFIF == FIF_GIF)
418   {
419     // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
420     aLoadFlags = GIF_PLAYBACK;
421   }
422   else if (aFIF == FIF_ICO)
423   {
424     // convert to 32bpp and create an alpha channel from the AND-mask when loading
425     aLoadFlags = ICO_MAKEALPHA;
426   }
427
428 #ifdef _WIN32
429   FIBITMAP* anImage = FreeImage_LoadU (aFIF, aFileNameW.ToWideString(), aLoadFlags);
430 #else
431   FIBITMAP* anImage = FreeImage_Load  (aFIF, theImagePath.ToCString(), aLoadFlags);
432 #endif
433   if (anImage == NULL)
434   {
435     TCollection_AsciiString aMessage = "Error: image file '";
436     aMessage.AssignCat (theImagePath);
437     aMessage.AssignCat ("' is missing or invalid.");
438     ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
439     return false;
440   }
441
442   Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
443                                                 FreeImage_GetColorType(anImage),
444                                                 FreeImage_GetBPP      (anImage));
445   if (aFormat == Image_Format_UNKNOWN)
446   {
447     //anImage = FreeImage_ConvertTo24Bits (anImage);
448     TCollection_AsciiString aMessage = "Error: image file '";
449     aMessage.AssignCat (theImagePath);
450     aMessage.AssignCat ("' has unsupported pixel format.");
451     ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
452     return false;
453   }
454
455   Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
456                              FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
457   SetTopDown (false);
458
459   // assign image after wrapper initialization (virtual Clear() called inside)
460   myLibImage = anImage;
461   return true;
462 }
463 #elif defined(HAVE_WINCODEC)
464 bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath)
465 {
466   Clear();
467
468   IWICImagingFactory* aWicImgFactory = NULL;
469   CoInitializeEx (NULL, COINIT_MULTITHREADED);
470   if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory)) != S_OK)
471   {
472     Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail);
473     return false;
474   }
475
476   Image_ComPtr<IWICBitmapDecoder> aWicDecoder;
477   const TCollection_ExtendedString aFileNameW (theImagePath);
478   if (aWicImgFactory->CreateDecoderFromFilename (aFileNameW.ToWideString(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK)
479   {
480     Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail);
481     return false;
482   }
483
484   UINT aFrameCount = 0, aFrameSizeX = 0, aFrameSizeY = 0;
485   WICPixelFormatGUID aWicPixelFormat = getNullGuid();
486   Image_ComPtr<IWICBitmapFrameDecode> aWicFrameDecode;
487   if (aWicDecoder->GetFrameCount (&aFrameCount) != S_OK
488    || aFrameCount < 1
489    || aWicDecoder->GetFrame (0, &aWicFrameDecode.ChangePtr()) != S_OK
490    || aWicFrameDecode->GetSize (&aFrameSizeX, &aFrameSizeY) != S_OK
491    || aWicFrameDecode->GetPixelFormat (&aWicPixelFormat))
492   {
493     Message::DefaultMessenger()->Send ("Error: cannot get WIC Image Frame", Message_Fail);
494     return false;
495   }
496
497   Image_ComPtr<IWICFormatConverter> aWicConvertedFrame;
498   Image_Format aPixelFormat = convertFromWicFormat (aWicPixelFormat);
499   if (aPixelFormat == Image_Format_UNKNOWN)
500   {
501     aPixelFormat = Image_Format_RGB;
502     if (aWicImgFactory->CreateFormatConverter (&aWicConvertedFrame.ChangePtr()) != S_OK
503      || aWicConvertedFrame->Initialize (aWicFrameDecode.get(), convertToWicFormat (aPixelFormat), WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom) != S_OK)
504     {
505       Message::DefaultMessenger()->Send ("Error: cannot convert WIC Image Frame to RGB format", Message_Fail);
506       return false;
507     }
508     aWicFrameDecode.Nullify();
509   }
510
511   if (!Image_PixMap::InitTrash (aPixelFormat, aFrameSizeX, aFrameSizeY))
512   {
513     Message::DefaultMessenger()->Send ("Error: cannot initialize memory for image", Message_Fail);
514     return false;
515   }
516
517   IWICBitmapSource* aWicSrc = aWicFrameDecode.get();
518   if(!aWicConvertedFrame.IsNull())
519   {
520     aWicSrc = aWicConvertedFrame.get();
521   }
522   if (aWicSrc->CopyPixels (NULL, (UINT )SizeRowBytes(), (UINT )SizeBytes(), ChangeData()) != S_OK)
523   {
524     Message::DefaultMessenger()->Send ("Error: cannot copy pixels from WIC Image", Message_Fail);
525     return false;
526   }
527   SetTopDown (true);
528   return true;
529 }
530 #else
531 bool Image_AlienPixMap::Load (const TCollection_AsciiString&)
532 {
533   Clear();
534   return false;
535 }
536 #endif
537
538 // =======================================================================
539 // function : savePPM
540 // purpose  :
541 // =======================================================================
542 bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const
543 {
544   if (IsEmpty())
545   {
546     return false;
547   }
548
549   // Open file
550   FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb");
551   if (aFile == NULL)
552   {
553     return false;
554   }
555
556   // Write header
557   fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY());
558   fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n");
559
560   // Write pixel data
561   Standard_Byte aByte;
562   for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
563   {
564     for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
565     {
566       // extremely SLOW but universal (implemented for all supported pixel formats)
567       const Quantity_ColorRGBA aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow);
568       aByte = Standard_Byte(aColor.GetRGB().Red()   * 255.0); fwrite (&aByte, 1, 1, aFile);
569       aByte = Standard_Byte(aColor.GetRGB().Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
570       aByte = Standard_Byte(aColor.GetRGB().Blue()  * 255.0); fwrite (&aByte, 1, 1, aFile);
571     }
572   }
573
574   // Close file
575   fclose (aFile);
576   return true;
577 }
578
579 // =======================================================================
580 // function : Save
581 // purpose  :
582 // =======================================================================
583 bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName)
584 {
585 #ifdef HAVE_FREEIMAGE
586   if (myLibImage == NULL)
587   {
588     return false;
589   }
590
591 #ifdef _WIN32
592   const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True);
593   FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU (aFileNameW.ToWideString());
594 #else
595   FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString());
596 #endif
597   if (anImageFormat == FIF_UNKNOWN)
598   {
599 #ifdef OCCT_DEBUG
600     std::cerr << "Image_PixMap, image format doesn't supported!\n";
601 #endif
602     return false;
603   }
604
605   if (IsTopDown())
606   {
607     FreeImage_FlipVertical (myLibImage);
608     SetTopDown (false);
609   }
610
611   // FreeImage doesn't provide flexible format conversion API
612   // so we should perform multiple conversions in some cases!
613   FIBITMAP* anImageToDump = myLibImage;
614   switch (anImageFormat)
615   {
616     case FIF_PNG:
617     case FIF_BMP:
618     {
619       if (Format() == Image_Format_BGR32
620        || Format() == Image_Format_RGB32)
621       {
622         // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
623         for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
624         {
625           for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
626           {
627             myData.ChangeValue (aRow, aCol)[3] = 0xFF;
628           }
629         }
630       }
631       else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
632       {
633         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
634       }
635       break;
636     }
637     case FIF_GIF:
638     {
639       FIBITMAP* aTmpBitmap = myLibImage;
640       if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
641       {
642         aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
643         if (aTmpBitmap == NULL)
644         {
645           return false;
646         }
647       }
648
649       if (FreeImage_GetBPP (aTmpBitmap) != 24)
650       {
651         FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
652         if (aTmpBitmap != myLibImage)
653         {
654           FreeImage_Unload (aTmpBitmap);
655         }
656         if (aTmpBitmap24 == NULL)
657         {
658           return false;
659         }
660         aTmpBitmap = aTmpBitmap24;
661       }
662
663       // need conversion to image with palette (requires 24bit bitmap)
664       anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
665       if (aTmpBitmap != myLibImage)
666       {
667         FreeImage_Unload (aTmpBitmap);
668       }
669       break;
670     }
671     case FIF_HDR:
672     case FIF_EXR:
673     {
674       if (Format() == Image_Format_Gray
675        || Format() == Image_Format_Alpha)
676       {
677         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
678       }
679       else if (Format() == Image_Format_RGBA
680             || Format() == Image_Format_BGRA)
681       {
682         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
683       }
684       else
685       {
686         FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
687         if (aImgTypeFI != FIT_RGBF
688          && aImgTypeFI != FIT_RGBAF
689          && aImgTypeFI != FIT_FLOAT)
690         {
691           anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
692         }
693       }
694       break;
695     }
696     default:
697     {
698       if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
699       {
700         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
701         if (anImageToDump == NULL)
702         {
703           return false;
704         }
705       }
706
707       if (FreeImage_GetBPP (anImageToDump) != 24)
708       {
709         FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
710         if (anImageToDump != myLibImage)
711         {
712           FreeImage_Unload (anImageToDump);
713         }
714         if (aTmpBitmap24 == NULL)
715         {
716           return false;
717         }
718         anImageToDump = aTmpBitmap24;
719       }
720       break;
721     }
722   }
723
724   if (anImageToDump == NULL)
725   {
726     return false;
727   }
728
729 #ifdef _WIN32
730   bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString()) != FALSE);
731 #else
732   bool isSaved = (FreeImage_Save  (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE);
733 #endif
734   if (anImageToDump != myLibImage)
735   {
736     FreeImage_Unload (anImageToDump);
737   }
738   return isSaved;
739
740 #elif defined(HAVE_WINCODEC)
741
742   TCollection_AsciiString aFileNameLower = theFileName;
743   aFileNameLower.LowerCase();
744   GUID aFileFormat = getNullGuid();
745   if (aFileNameLower.EndsWith (".ppm"))
746   {
747     return savePPM (theFileName);
748   }
749   else if (aFileNameLower.EndsWith (".bmp"))
750   {
751     aFileFormat = GUID_ContainerFormatBmp;
752   }
753   else if (aFileNameLower.EndsWith (".png"))
754   {
755     aFileFormat = GUID_ContainerFormatPng;
756   }
757   else if (aFileNameLower.EndsWith (".jpg")
758         || aFileNameLower.EndsWith (".jpeg"))
759   {
760     aFileFormat = GUID_ContainerFormatJpeg;
761   }
762   else if (aFileNameLower.EndsWith (".tiff"))
763   {
764     aFileFormat = GUID_ContainerFormatTiff;
765   }
766   else if (aFileNameLower.EndsWith (".gif"))
767   {
768     aFileFormat = GUID_ContainerFormatGif;
769   }
770
771   if (aFileFormat == getNullGuid())
772   {
773     Message::DefaultMessenger()->Send ("Error: unsupported image format", Message_Fail);
774     return false;
775   }
776
777   IWICImagingFactory* aWicImgFactory = NULL;
778   CoInitializeEx (NULL, COINIT_MULTITHREADED);
779   if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory)) != S_OK)
780   {
781     Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail);
782     return false;
783   }
784
785   Image_ComPtr<IWICStream> aWicFileStream;
786   Image_ComPtr<IWICBitmapEncoder> aWicEncoder;
787   const TCollection_ExtendedString aFileNameW (theFileName);
788   if (aWicImgFactory->CreateStream (&aWicFileStream.ChangePtr()) != S_OK
789    || aWicFileStream->InitializeFromFilename (aFileNameW.ToWideString(), GENERIC_WRITE) != S_OK)
790   {
791     Message::DefaultMessenger()->Send ("Error: cannot create WIC File Stream", Message_Fail);
792     return false;
793   }
794   if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK
795    || aWicEncoder->Initialize (aWicFileStream.get(), WICBitmapEncoderNoCache) != S_OK)
796   {
797     Message::DefaultMessenger()->Send ("Error: cannot create WIC Encoder", Message_Fail);
798     return false;
799   }
800
801   const WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat);
802   if (aWicPixelFormat == getNullGuid())
803   {
804     Message::DefaultMessenger()->Send ("Error: unsupported pixel format", Message_Fail);
805     return false;
806   }
807
808   WICPixelFormatGUID aWicPixelFormatRes = aWicPixelFormat;
809   Image_ComPtr<IWICBitmapFrameEncode> aWicFrameEncode;
810   if (aWicEncoder->CreateNewFrame (&aWicFrameEncode.ChangePtr(), NULL) != S_OK
811    || aWicFrameEncode->Initialize (NULL) != S_OK
812    || aWicFrameEncode->SetSize ((UINT )SizeX(), (UINT )SizeY()) != S_OK
813    || aWicFrameEncode->SetPixelFormat (&aWicPixelFormatRes) != S_OK)
814   {
815     Message::DefaultMessenger()->Send ("Error: cannot create WIC Frame", Message_Fail);
816     return false;
817   }
818
819   if (aWicPixelFormatRes != aWicPixelFormat)
820   {
821     Message::DefaultMessenger()->Send ("Error: pixel format is unsupported by image format", Message_Fail);
822     return false;
823   }
824
825   if (IsTopDown())
826   {
827     if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )Data()) != S_OK)
828     {
829       Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail);
830       return false;
831     }
832   }
833   else
834   {
835     for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
836     {
837       if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )Row (aRow)) != S_OK)
838       {
839         Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail);
840         return false;
841       }
842     }
843   }
844
845   if (aWicFrameEncode->Commit() != S_OK
846    || aWicEncoder->Commit() != S_OK)
847   {
848     Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC Frame", Message_Fail);
849     return false;
850   }
851   if (aWicFileStream->Commit (STGC_DEFAULT) != S_OK)
852   {
853     //Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC File Stream", Message_Fail);
854     //return false;
855   }
856   return true;
857 #else
858   const Standard_Integer aLen = theFileName.Length();
859   if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
860       && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 )
861   {
862     return savePPM (theFileName);
863   }
864 #ifdef OCCT_DEBUG
865   std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n";
866 #endif
867   return savePPM (theFileName);
868 #endif
869 }
870
871 // =======================================================================
872 // function : AdjustGamma
873 // purpose  :
874 // =======================================================================
875 bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr)
876 {
877 #ifdef HAVE_FREEIMAGE
878   return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE;
879 #else
880   (void )theGammaCorr;
881   return false;
882 #endif
883 }