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