0031501: Foundation Classes, Message_Printer - remove theToPutEndl argument -- use...
[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::SendFail (TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported file format");
552     if (aFiMem != NULL)
553     {
554       FreeImage_CloseMemory (aFiMem);
555     }
556     return false;
557   }
558
559   int aLoadFlags = 0;
560   if (aFIF == FIF_GIF)
561   {
562     // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
563     aLoadFlags = GIF_PLAYBACK;
564   }
565   else if (aFIF == FIF_ICO)
566   {
567     // convert to 32bpp and create an alpha channel from the AND-mask when loading
568     aLoadFlags = ICO_MAKEALPHA;
569   }
570
571   FIBITMAP* anImage = NULL;
572   if (theData != NULL)
573   {
574     anImage = FreeImage_LoadFromMemory (aFIF, aFiMem, aLoadFlags);
575     FreeImage_CloseMemory (aFiMem);
576     aFiMem = NULL;
577   }
578   else
579   {
580   #ifdef _WIN32
581     anImage = FreeImage_LoadU (aFIF, aFileNameW.ToWideString(), aLoadFlags);
582   #else
583     anImage = FreeImage_Load  (aFIF, theImagePath.ToCString(), aLoadFlags);
584   #endif
585   }
586   if (anImage == NULL)
587   {
588     ::Message::SendFail (TCollection_AsciiString ("Error: image file '") + theImagePath  + "' is missing or invalid");
589     return false;
590   }
591
592   Image_Format aFormat = Image_Format_UNKNOWN;
593   if (FreeImage_GetBPP (anImage) == 1)
594   {
595     FIBITMAP* aTmpImage = FreeImage_ConvertTo8Bits (anImage);
596     FreeImage_Unload (anImage);
597     anImage = aTmpImage;
598   }
599   if (anImage != NULL)
600   {
601     aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
602                                      FreeImage_GetColorType(anImage),
603                                      FreeImage_GetBPP      (anImage));
604     if (aFormat == Image_Format_UNKNOWN)
605     {
606       FIBITMAP* aTmpImage = FreeImage_ConvertTo24Bits (anImage);
607       FreeImage_Unload (anImage);
608       anImage = aTmpImage;
609       if (anImage != NULL)
610       {
611         aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
612                                          FreeImage_GetColorType(anImage),
613                                          FreeImage_GetBPP      (anImage));
614       }
615     }
616   }
617   if (aFormat == Image_Format_UNKNOWN)
618   {
619     ::Message::SendFail (TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported pixel format");
620     return false;
621   }
622
623   Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
624                              FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
625   SetTopDown (false);
626
627   // assign image after wrapper initialization (virtual Clear() called inside)
628   myLibImage = anImage;
629   return true;
630 }
631
632 bool Image_AlienPixMap::Load (std::istream& theStream,
633                               const TCollection_AsciiString& theFileName)
634 {
635   Clear();
636
637   Image_FreeImageStream aStream (theStream);
638   FreeImageIO aFiIO = aStream.GetFiIO();
639
640   FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeFromHandle (&aFiIO, &aStream, 0);
641   if (aFIF == FIF_UNKNOWN)
642   {
643     // no signature? try to guess the file format from the file extension
644     aFIF = FreeImage_GetFIFFromFilename (theFileName.ToCString());
645   }
646   if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
647   {
648     ::Message::SendFail (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported file format");
649     return false;
650   }
651
652   int aLoadFlags = 0;
653   if (aFIF == FIF_GIF)
654   {
655     // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
656     aLoadFlags = GIF_PLAYBACK;
657   }
658   else if (aFIF == FIF_ICO)
659   {
660     // convert to 32bpp and create an alpha channel from the AND-mask when loading
661     aLoadFlags = ICO_MAKEALPHA;
662   }
663
664   FIBITMAP* anImage = FreeImage_LoadFromHandle (aFIF, &aFiIO, &aStream, aLoadFlags);
665   if (anImage == NULL)
666   {
667     ::Message::SendFail (TCollection_AsciiString ("Error: image stream '") + theFileName + "' is missing or invalid");
668     return false;
669   }
670
671   Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
672                                                 FreeImage_GetColorType(anImage),
673                                                 FreeImage_GetBPP      (anImage));
674   if (aFormat == Image_Format_UNKNOWN)
675   {
676     ::Message::SendFail (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported pixel format");
677     return false;
678   }
679
680   Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
681                              FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
682   SetTopDown (false);
683
684   // assign image after wrapper initialization (virtual Clear() called inside)
685   myLibImage = anImage;
686   return true;
687 }
688
689 #elif defined(HAVE_WINCODEC)
690 bool Image_AlienPixMap::Load (const Standard_Byte* theData,
691                               Standard_Size theLength,
692                               const TCollection_AsciiString& theFileName)
693 {
694   Clear();
695
696   Image_ComPtr<IWICImagingFactory> aWicImgFactory;
697   CoInitializeEx (NULL, COINIT_MULTITHREADED);
698   if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK)
699   {
700     Message::SendFail ("Error: cannot initialize WIC Imaging Factory");
701     return false;
702   }
703
704   Image_ComPtr<IWICBitmapDecoder> aWicDecoder;
705   Image_ComPtr<IWICStream> aWicStream;
706   if (theData != NULL)
707   {
708     if (aWicImgFactory->CreateStream (&aWicStream.ChangePtr()) != S_OK
709      || aWicStream->InitializeFromMemory ((BYTE* )theData, (DWORD )theLength) != S_OK)
710     {
711       Message::SendFail ("Error: cannot initialize WIC Stream");
712       return false;
713     }
714     if (aWicImgFactory->CreateDecoderFromStream (aWicStream.get(), NULL, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK)
715     {
716       Message::SendFail ("Error: cannot create WIC Image Decoder");
717       return false;
718     }
719   }
720   else
721   {
722     const TCollection_ExtendedString aFileNameW (theFileName);
723     if (aWicImgFactory->CreateDecoderFromFilename (aFileNameW.ToWideString(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK)
724     {
725       Message::SendFail ("Error: cannot create WIC Image Decoder");
726       return false;
727     }
728   }
729
730   UINT aFrameCount = 0, aFrameSizeX = 0, aFrameSizeY = 0;
731   WICPixelFormatGUID aWicPixelFormat = getNullGuid();
732   Image_ComPtr<IWICBitmapFrameDecode> aWicFrameDecode;
733   if (aWicDecoder->GetFrameCount (&aFrameCount) != S_OK
734    || aFrameCount < 1
735    || aWicDecoder->GetFrame (0, &aWicFrameDecode.ChangePtr()) != S_OK
736    || aWicFrameDecode->GetSize (&aFrameSizeX, &aFrameSizeY) != S_OK
737    || aWicFrameDecode->GetPixelFormat (&aWicPixelFormat))
738   {
739     Message::SendFail ("Error: cannot get WIC Image Frame");
740     return false;
741   }
742
743   Image_ComPtr<IWICFormatConverter> aWicConvertedFrame;
744   Image_Format aPixelFormat = convertFromWicFormat (aWicPixelFormat);
745   if (aPixelFormat == Image_Format_UNKNOWN)
746   {
747     aPixelFormat = Image_Format_RGB;
748     if (aWicImgFactory->CreateFormatConverter (&aWicConvertedFrame.ChangePtr()) != S_OK
749      || aWicConvertedFrame->Initialize (aWicFrameDecode.get(), convertToWicFormat (aPixelFormat), WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom) != S_OK)
750     {
751       Message::SendFail ("Error: cannot convert WIC Image Frame to RGB format");
752       return false;
753     }
754     aWicFrameDecode.Nullify();
755   }
756
757   if (!Image_PixMap::InitTrash (aPixelFormat, aFrameSizeX, aFrameSizeY))
758   {
759     Message::SendFail ("Error: cannot initialize memory for image");
760     return false;
761   }
762
763   IWICBitmapSource* aWicSrc = aWicFrameDecode.get();
764   if(!aWicConvertedFrame.IsNull())
765   {
766     aWicSrc = aWicConvertedFrame.get();
767   }
768   if (aWicSrc->CopyPixels (NULL, (UINT )SizeRowBytes(), (UINT )SizeBytes(), ChangeData()) != S_OK)
769   {
770     Message::SendFail ("Error: cannot copy pixels from WIC Image");
771     return false;
772   }
773   SetTopDown (true);
774   return true;
775 }
776 bool Image_AlienPixMap::Load (std::istream& theStream,
777                               const TCollection_AsciiString& theFilePath)
778 {
779   Clear();
780
781   // fallback copying stream data into transient buffer
782   const std::streamoff aStart = theStream.tellg();
783   theStream.seekg (0, std::ios::end);
784   const Standard_Integer aLen = Standard_Integer(theStream.tellg() - aStart);
785   theStream.seekg (aStart);
786   if (aLen <= 0)
787   {
788     Message::SendFail ("Error: empty stream");
789     return false;
790   }
791
792   NCollection_Array1<Standard_Byte> aBuff (1, aLen);
793   if (!theStream.read ((char* )&aBuff.ChangeFirst(), aBuff.Size()))
794   {
795     Message::SendFail ("Error: unable to read stream");
796     return false;
797   }
798
799   return Load (&aBuff.ChangeFirst(), aBuff.Size(), theFilePath);
800 }
801 #else
802 bool Image_AlienPixMap::Load (std::istream& ,
803                               const TCollection_AsciiString& )
804 {
805   Clear();
806   Message::SendFail ("Error: no image library available");
807   return false;
808 }
809 bool Image_AlienPixMap::Load (const Standard_Byte* ,
810                               Standard_Size ,
811                               const TCollection_AsciiString& )
812 {
813   Clear();
814   Message::SendFail ("Error: no image library available");
815   return false;
816 }
817 #endif
818
819 // =======================================================================
820 // function : savePPM
821 // purpose  :
822 // =======================================================================
823 bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const
824 {
825   if (IsEmpty())
826   {
827     return false;
828   }
829
830   // Open file
831   FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb");
832   if (aFile == NULL)
833   {
834     return false;
835   }
836
837   // Write header
838   fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY());
839   fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n");
840
841   // Write pixel data
842   Standard_Byte aByte;
843   for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
844   {
845     for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
846     {
847       // extremely SLOW but universal (implemented for all supported pixel formats)
848       const Quantity_ColorRGBA aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow);
849       aByte = Standard_Byte(aColor.GetRGB().Red()   * 255.0); fwrite (&aByte, 1, 1, aFile);
850       aByte = Standard_Byte(aColor.GetRGB().Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
851       aByte = Standard_Byte(aColor.GetRGB().Blue()  * 255.0); fwrite (&aByte, 1, 1, aFile);
852     }
853   }
854
855   // Close file
856   fclose (aFile);
857   return true;
858 }
859
860 // =======================================================================
861 // function : Save
862 // purpose  :
863 // =======================================================================
864 bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName)
865 {
866 #ifdef HAVE_FREEIMAGE
867   if (myLibImage == NULL)
868   {
869     return false;
870   }
871
872 #ifdef _WIN32
873   const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True);
874   FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU (aFileNameW.ToWideString());
875 #else
876   FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString());
877 #endif
878   if (anImageFormat == FIF_UNKNOWN)
879   {
880 #ifdef OCCT_DEBUG
881     std::cerr << "Image_PixMap, image format doesn't supported!\n";
882 #endif
883     return false;
884   }
885
886   if (IsTopDown())
887   {
888     FreeImage_FlipVertical (myLibImage);
889     SetTopDown (false);
890   }
891
892   // FreeImage doesn't provide flexible format conversion API
893   // so we should perform multiple conversions in some cases!
894   FIBITMAP* anImageToDump = myLibImage;
895   switch (anImageFormat)
896   {
897     case FIF_PNG:
898     case FIF_BMP:
899     {
900       if (Format() == Image_Format_BGR32
901        || Format() == Image_Format_RGB32)
902       {
903         // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
904         for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
905         {
906           for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
907           {
908             myData.ChangeValue (aRow, aCol)[3] = 0xFF;
909           }
910         }
911       }
912       else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
913       {
914         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
915       }
916       break;
917     }
918     case FIF_GIF:
919     {
920       FIBITMAP* aTmpBitmap = myLibImage;
921       if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
922       {
923         aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
924         if (aTmpBitmap == NULL)
925         {
926           return false;
927         }
928       }
929
930       if (FreeImage_GetBPP (aTmpBitmap) != 24)
931       {
932         FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
933         if (aTmpBitmap != myLibImage)
934         {
935           FreeImage_Unload (aTmpBitmap);
936         }
937         if (aTmpBitmap24 == NULL)
938         {
939           return false;
940         }
941         aTmpBitmap = aTmpBitmap24;
942       }
943
944       // need conversion to image with palette (requires 24bit bitmap)
945       anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
946       if (aTmpBitmap != myLibImage)
947       {
948         FreeImage_Unload (aTmpBitmap);
949       }
950       break;
951     }
952     case FIF_HDR:
953     case FIF_EXR:
954     {
955       if (Format() == Image_Format_Gray
956        || Format() == Image_Format_Alpha)
957       {
958         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
959       }
960       else if (Format() == Image_Format_RGBA
961             || Format() == Image_Format_BGRA)
962       {
963         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
964       }
965       else
966       {
967         FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
968         if (aImgTypeFI != FIT_RGBF
969          && aImgTypeFI != FIT_RGBAF
970          && aImgTypeFI != FIT_FLOAT)
971         {
972           anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
973         }
974       }
975       break;
976     }
977     default:
978     {
979       if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
980       {
981         anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
982         if (anImageToDump == NULL)
983         {
984           return false;
985         }
986       }
987
988       if (FreeImage_GetBPP (anImageToDump) != 24)
989       {
990         FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
991         if (anImageToDump != myLibImage)
992         {
993           FreeImage_Unload (anImageToDump);
994         }
995         if (aTmpBitmap24 == NULL)
996         {
997           return false;
998         }
999         anImageToDump = aTmpBitmap24;
1000       }
1001       break;
1002     }
1003   }
1004
1005   if (anImageToDump == NULL)
1006   {
1007     return false;
1008   }
1009
1010 #ifdef _WIN32
1011   bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString()) != FALSE);
1012 #else
1013   bool isSaved = (FreeImage_Save  (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE);
1014 #endif
1015   if (anImageToDump != myLibImage)
1016   {
1017     FreeImage_Unload (anImageToDump);
1018   }
1019   return isSaved;
1020
1021 #elif defined(HAVE_WINCODEC)
1022
1023   TCollection_AsciiString aFileNameLower = theFileName;
1024   aFileNameLower.LowerCase();
1025   GUID aFileFormat = getNullGuid();
1026   if (aFileNameLower.EndsWith (".ppm"))
1027   {
1028     return savePPM (theFileName);
1029   }
1030   else if (aFileNameLower.EndsWith (".bmp"))
1031   {
1032     aFileFormat = GUID_ContainerFormatBmp;
1033   }
1034   else if (aFileNameLower.EndsWith (".png"))
1035   {
1036     aFileFormat = GUID_ContainerFormatPng;
1037   }
1038   else if (aFileNameLower.EndsWith (".jpg")
1039         || aFileNameLower.EndsWith (".jpeg"))
1040   {
1041     aFileFormat = GUID_ContainerFormatJpeg;
1042   }
1043   else if (aFileNameLower.EndsWith (".tiff"))
1044   {
1045     aFileFormat = GUID_ContainerFormatTiff;
1046   }
1047   else if (aFileNameLower.EndsWith (".gif"))
1048   {
1049     aFileFormat = GUID_ContainerFormatGif;
1050   }
1051
1052   if (aFileFormat == getNullGuid())
1053   {
1054     Message::SendFail ("Error: unsupported image format");
1055     return false;
1056   }
1057
1058   Image_ComPtr<IWICImagingFactory> aWicImgFactory;
1059   CoInitializeEx (NULL, COINIT_MULTITHREADED);
1060   if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK)
1061   {
1062     Message::SendFail ("Error: cannot initialize WIC Imaging Factory");
1063     return false;
1064   }
1065
1066   Image_ComPtr<IWICStream> aWicFileStream;
1067   Image_ComPtr<IWICBitmapEncoder> aWicEncoder;
1068   const TCollection_ExtendedString aFileNameW (theFileName);
1069   if (aWicImgFactory->CreateStream (&aWicFileStream.ChangePtr()) != S_OK
1070    || aWicFileStream->InitializeFromFilename (aFileNameW.ToWideString(), GENERIC_WRITE) != S_OK)
1071   {
1072     Message::SendFail ("Error: cannot create WIC File Stream");
1073     return false;
1074   }
1075   if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK
1076    || aWicEncoder->Initialize (aWicFileStream.get(), WICBitmapEncoderNoCache) != S_OK)
1077   {
1078     Message::SendFail ("Error: cannot create WIC Encoder");
1079     return false;
1080   }
1081
1082   const WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat);
1083   if (aWicPixelFormat == getNullGuid())
1084   {
1085     Message::SendFail ("Error: unsupported pixel format");
1086     return false;
1087   }
1088
1089   WICPixelFormatGUID aWicPixelFormatRes = aWicPixelFormat;
1090   Image_ComPtr<IWICBitmapFrameEncode> aWicFrameEncode;
1091   if (aWicEncoder->CreateNewFrame (&aWicFrameEncode.ChangePtr(), NULL) != S_OK
1092    || aWicFrameEncode->Initialize (NULL) != S_OK
1093    || aWicFrameEncode->SetSize ((UINT )SizeX(), (UINT )SizeY()) != S_OK
1094    || aWicFrameEncode->SetPixelFormat (&aWicPixelFormatRes) != S_OK)
1095   {
1096     Message::SendFail ("Error: cannot create WIC Frame");
1097     return false;
1098   }
1099
1100   if (aWicPixelFormatRes != aWicPixelFormat)
1101   {
1102     Message::SendFail ("Error: pixel format is unsupported by image format");
1103     return false;
1104   }
1105
1106   if (IsTopDown())
1107   {
1108     if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )Data()) != S_OK)
1109     {
1110       Message::SendFail ("Error: cannot write pixels to WIC Frame");
1111       return false;
1112     }
1113   }
1114   else
1115   {
1116     for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
1117     {
1118       if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )Row (aRow)) != S_OK)
1119       {
1120         Message::SendFail ("Error: cannot write pixels to WIC Frame");
1121         return false;
1122       }
1123     }
1124   }
1125
1126   if (aWicFrameEncode->Commit() != S_OK
1127    || aWicEncoder->Commit() != S_OK)
1128   {
1129     Message::SendFail ("Error: cannot commit data to WIC Frame");
1130     return false;
1131   }
1132   if (aWicFileStream->Commit (STGC_DEFAULT) != S_OK)
1133   {
1134     //Message::Send ("Error: cannot commit data to WIC File Stream", Message_Fail);
1135     //return false;
1136   }
1137   return true;
1138 #else
1139   const Standard_Integer aLen = theFileName.Length();
1140   if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
1141       && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 )
1142   {
1143     return savePPM (theFileName);
1144   }
1145   Message::SendTrace ("Image_PixMap, no image library available! Image saved in PPM format");
1146   return savePPM (theFileName);
1147 #endif
1148 }
1149
1150 // =======================================================================
1151 // function : AdjustGamma
1152 // purpose  :
1153 // =======================================================================
1154 bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr)
1155 {
1156 #ifdef HAVE_FREEIMAGE
1157   return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE;
1158 #else
1159   (void )theGammaCorr;
1160   return false;
1161 #endif
1162 }