0030991: Draw Harness - ViewerTest::ParseColor() defines out-of-range alpha component
[occt.git] / src / Image / Image_AlienPixMap.cxx
CommitLineData
692613e5 1// Created on: 2010-09-16
2// Created by: KGV
973c2be1 3// Copyright (c) 2010-2014 OPEN CASCADE SAS
692613e5 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
692613e5 6//
d5f74e42 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
973c2be1 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.
692613e5 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
692613e5 15
a975e06e 16#if !defined(HAVE_FREEIMAGE) && defined(_WIN32)
17 #define HAVE_WINCODEC
18#endif
19
692613e5 20#ifdef HAVE_FREEIMAGE
21 #include <FreeImage.h>
22
23 #ifdef _MSC_VER
24 #pragma comment( lib, "FreeImage.lib" )
25 #endif
a975e06e 26#elif defined(HAVE_WINCODEC)
a975e06e 27 #include <wincodec.h>
0616aa9e 28 // prevent warnings on MSVC10
29 #include <Standard_WarningsDisable.hxx>
30 #include <Standard_TypeDef.hxx>
31 #include <Standard_WarningsRestore.hxx>
a975e06e 32 #undef min
33 #undef max
9196ea9d 34
35 #ifdef _MSC_VER
36 #pragma comment(lib, "Ole32.lib")
37 #endif
692613e5 38#endif
39
40#include <Image_AlienPixMap.hxx>
41#include <gp.hxx>
0c015ee2 42#include <Message.hxx>
43#include <Message_Messenger.hxx>
88b12b7c 44#include <NCollection_Array1.hxx>
45#include <Standard_ArrayStreamBuffer.hxx>
692613e5 46#include <TCollection_AsciiString.hxx>
7aa1b65c 47#include <TCollection_ExtendedString.hxx>
94708556 48#include <OSD_OpenFile.hxx>
0616aa9e 49
692613e5 50#include <fstream>
a096a7a5 51#include <algorithm>
692613e5 52
f5f4ebd0 53IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap,Image_PixMap)
54
692613e5 55namespace
56{
a975e06e 57#ifdef HAVE_FREEIMAGE
dc858f4c 58 static Image_Format convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI,
59 FREE_IMAGE_COLOR_TYPE theColorTypeFI,
60 unsigned theBitsPerPixel)
692613e5 61 {
62 switch (theFormatFI)
63 {
dc858f4c 64 case FIT_RGBF: return Image_Format_RGBF;
65 case FIT_RGBAF: return Image_Format_RGBAF;
66 case FIT_FLOAT: return Image_Format_GrayF;
692613e5 67 case FIT_BITMAP:
68 {
69 switch (theColorTypeFI)
70 {
71 case FIC_MINISBLACK:
72 {
dc858f4c 73 return Image_Format_Gray;
692613e5 74 }
75 case FIC_RGB:
76 {
77 if (Image_PixMap::IsBigEndianHost())
78 {
dc858f4c 79 return (theBitsPerPixel == 32) ? Image_Format_RGB32 : Image_Format_RGB;
692613e5 80 }
81 else
82 {
dc858f4c 83 return (theBitsPerPixel == 32) ? Image_Format_BGR32 : Image_Format_BGR;
692613e5 84 }
85 }
86 case FIC_RGBALPHA:
87 {
dc858f4c 88 return Image_PixMap::IsBigEndianHost() ? Image_Format_RGBA : Image_Format_BGRA;
692613e5 89 }
90 default:
dc858f4c 91 return Image_Format_UNKNOWN;
692613e5 92 }
93 }
94 default:
dc858f4c 95 return Image_Format_UNKNOWN;
692613e5 96 }
97 }
98
dc858f4c 99 static FREE_IMAGE_TYPE convertToFreeFormat (Image_Format theFormat)
692613e5 100 {
101 switch (theFormat)
102 {
dc858f4c 103 case Image_Format_GrayF:
104 case Image_Format_AlphaF:
692613e5 105 return FIT_FLOAT;
dc858f4c 106 case Image_Format_RGBAF:
692613e5 107 return FIT_RGBAF;
dc858f4c 108 case Image_Format_RGBF:
692613e5 109 return FIT_RGBF;
dc858f4c 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:
692613e5 118 return FIT_BITMAP;
119 default:
120 return FIT_UNKNOWN;
121 }
122 }
88b12b7c 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
a975e06e 226#elif defined(HAVE_WINCODEC)
692613e5 227
a975e06e 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}
692613e5 332
333// =======================================================================
334// function : Image_AlienPixMap
335// purpose :
336// =======================================================================
337Image_AlienPixMap::Image_AlienPixMap()
338: myLibImage (NULL)
339{
340 SetTopDown (false);
341}
342
343// =======================================================================
344// function : ~Image_AlienPixMap
345// purpose :
346// =======================================================================
347Image_AlienPixMap::~Image_AlienPixMap()
348{
349 Clear();
350}
351
352// =======================================================================
353// function : InitWrapper
354// purpose :
355// =======================================================================
dc858f4c 356bool Image_AlienPixMap::InitWrapper (Image_Format,
35e08fe8 357 Standard_Byte*,
358 const Standard_Size,
359 const Standard_Size,
360 const Standard_Size)
692613e5 361{
362 Clear();
363 return false;
364}
365
366// =======================================================================
367// function : InitTrash
368// purpose :
369// =======================================================================
498ce76b 370#ifdef HAVE_FREEIMAGE
dc858f4c 371bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat,
692613e5 372 const Standard_Size theSizeX,
373 const Standard_Size theSizeY,
498ce76b 374 const Standard_Size /*theSizeRowBytes*/)
692613e5 375{
376 Clear();
692613e5 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);
dc858f4c 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)
692613e5 391 {
392 //FreeImage_SetTransparent (anImage, FALSE);
dc858f4c 393 aFormat = (aFormat == Image_Format_BGRA) ? Image_Format_BGR32 : Image_Format_RGB32;
692613e5 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;
498ce76b 403}
a975e06e 404#elif defined(HAVE_WINCODEC)
405bool 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}
692613e5 434#else
dc858f4c 435bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat,
498ce76b 436 const Standard_Size theSizeX,
437 const Standard_Size theSizeY,
438 const Standard_Size theSizeRowBytes)
439{
692613e5 440 return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes);
692613e5 441}
498ce76b 442#endif
692613e5 443
444// =======================================================================
3c3131a0 445// function : InitCopy
692613e5 446// purpose :
447// =======================================================================
448bool 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 {
ca0c0b11 462 if (SizeRowBytes() == theCopy.SizeRowBytes()
463 && TopDownInc() == theCopy.TopDownInc())
692613e5 464 {
465 // copy with one call
ca0c0b11 466 memcpy (ChangeData(), theCopy.Data(), std::min (SizeBytes(), theCopy.SizeBytes()));
692613e5 467 return true;
468 }
469
470 // copy row-by-row
ca0c0b11 471 const Standard_Size aRowSizeBytes = std::min (SizeRowBytes(), theCopy.SizeRowBytes());
472 for (Standard_Size aRow = 0; aRow < myData.SizeY; ++aRow)
692613e5 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// =======================================================================
ca0c0b11 488void Image_AlienPixMap::Clear()
692613e5 489{
ca0c0b11 490 Image_PixMap::Clear();
692613e5 491#ifdef HAVE_FREEIMAGE
492 if (myLibImage != NULL)
493 {
494 FreeImage_Unload (myLibImage);
495 myLibImage = NULL;
496 }
497#endif
498}
499
88b12b7c 500// =======================================================================
501// function : IsTopDownDefault
502// purpose :
503// =======================================================================
504bool 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
692613e5 515// =======================================================================
516// function : Load
517// purpose :
518// =======================================================================
35e08fe8 519#ifdef HAVE_FREEIMAGE
88b12b7c 520bool Image_AlienPixMap::Load (const Standard_Byte* theData,
521 Standard_Size theLength,
522 const TCollection_AsciiString& theImagePath)
692613e5 523{
524 Clear();
7aa1b65c 525
526#ifdef _WIN32
a975e06e 527 const TCollection_ExtendedString aFileNameW (theImagePath);
7aa1b65c 528#endif
88b12b7c 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 }
692613e5 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 {
88b12b7c 551 ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported file format.",
552 Message_Fail);
553 if (aFiMem != NULL)
554 {
555 FreeImage_CloseMemory (aFiMem);
556 }
692613e5 557 return false;
558 }
559
560 int aLoadFlags = 0;
561 if (aFIF == FIF_GIF)
562 {
563 // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
564 aLoadFlags = GIF_PLAYBACK;
565 }
566 else if (aFIF == FIF_ICO)
567 {
568 // convert to 32bpp and create an alpha channel from the AND-mask when loading
569 aLoadFlags = ICO_MAKEALPHA;
570 }
571
88b12b7c 572 FIBITMAP* anImage = NULL;
573 if (theData != NULL)
574 {
575 anImage = FreeImage_LoadFromMemory (aFIF, aFiMem, aLoadFlags);
576 FreeImage_CloseMemory (aFiMem);
577 aFiMem = NULL;
578 }
579 else
580 {
581 #ifdef _WIN32
582 anImage = FreeImage_LoadU (aFIF, aFileNameW.ToWideString(), aLoadFlags);
583 #else
584 anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags);
585 #endif
586 }
692613e5 587 if (anImage == NULL)
588 {
0c015ee2 589 TCollection_AsciiString aMessage = "Error: image file '";
590 aMessage.AssignCat (theImagePath);
591 aMessage.AssignCat ("' is missing or invalid.");
592 ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
692613e5 593 return false;
594 }
595
fdae2107 596 if (FreeImage_GetBPP (anImage) == 1)
597 {
598 FIBITMAP* aTmpImage = FreeImage_ConvertTo8Bits (anImage);
599 FreeImage_Unload (anImage);
600 anImage = aTmpImage;
601 }
602
dc858f4c 603 Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
604 FreeImage_GetColorType(anImage),
605 FreeImage_GetBPP (anImage));
606 if (aFormat == Image_Format_UNKNOWN)
692613e5 607 {
608 //anImage = FreeImage_ConvertTo24Bits (anImage);
88b12b7c 609 ::Message::DefaultMessenger()->Send ( TCollection_AsciiString ("Error: image '") + theImagePath + "' has unsupported pixel format.",
610 Message_Fail);
692613e5 611 return false;
612 }
613
614 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
615 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
616 SetTopDown (false);
617
618 // assign image after wrapper initialization (virtual Clear() called inside)
619 myLibImage = anImage;
620 return true;
35e08fe8 621}
88b12b7c 622
623bool Image_AlienPixMap::Load (std::istream& theStream,
624 const TCollection_AsciiString& theFileName)
625{
626 Clear();
627
628 Image_FreeImageStream aStream (theStream);
629 FreeImageIO aFiIO = aStream.GetFiIO();
630
631 FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeFromHandle (&aFiIO, &aStream, 0);
632 if (aFIF == FIF_UNKNOWN)
633 {
634 // no signature? try to guess the file format from the file extension
635 aFIF = FreeImage_GetFIFFromFilename (theFileName.ToCString());
636 }
637 if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
638 {
639 ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported file format.",
640 Message_Fail);
641 return false;
642 }
643
644 int aLoadFlags = 0;
645 if (aFIF == FIF_GIF)
646 {
647 // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
648 aLoadFlags = GIF_PLAYBACK;
649 }
650 else if (aFIF == FIF_ICO)
651 {
652 // convert to 32bpp and create an alpha channel from the AND-mask when loading
653 aLoadFlags = ICO_MAKEALPHA;
654 }
655
656 FIBITMAP* anImage = FreeImage_LoadFromHandle (aFIF, &aFiIO, &aStream, aLoadFlags);
657 if (anImage == NULL)
658 {
659 ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' is missing or invalid.",
660 Message_Fail);
661 return false;
662 }
663
664 Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
665 FreeImage_GetColorType(anImage),
666 FreeImage_GetBPP (anImage));
667 if (aFormat == Image_Format_UNKNOWN)
668 {
669 ::Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: image stream '") + theFileName + "' has unsupported pixel format.",
670 Message_Fail);
671 return false;
672 }
673
674 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
675 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
676 SetTopDown (false);
677
678 // assign image after wrapper initialization (virtual Clear() called inside)
679 myLibImage = anImage;
680 return true;
681}
682
a975e06e 683#elif defined(HAVE_WINCODEC)
88b12b7c 684bool Image_AlienPixMap::Load (const Standard_Byte* theData,
685 Standard_Size theLength,
686 const TCollection_AsciiString& theFileName)
a975e06e 687{
688 Clear();
689
88b12b7c 690 Image_ComPtr<IWICImagingFactory> aWicImgFactory;
a975e06e 691 CoInitializeEx (NULL, COINIT_MULTITHREADED);
88b12b7c 692 if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK)
a975e06e 693 {
694 Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail);
695 return false;
696 }
697
698 Image_ComPtr<IWICBitmapDecoder> aWicDecoder;
88b12b7c 699 Image_ComPtr<IWICStream> aWicStream;
700 if (theData != NULL)
a975e06e 701 {
88b12b7c 702 if (aWicImgFactory->CreateStream (&aWicStream.ChangePtr()) != S_OK
703 || aWicStream->InitializeFromMemory ((BYTE* )theData, (DWORD )theLength) != S_OK)
704 {
705 Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Stream", Message_Fail);
706 return false;
707 }
708 if (aWicImgFactory->CreateDecoderFromStream (aWicStream.get(), NULL, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK)
709 {
710 Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail);
711 return false;
712 }
713 }
714 else
715 {
716 const TCollection_ExtendedString aFileNameW (theFileName);
717 if (aWicImgFactory->CreateDecoderFromFilename (aFileNameW.ToWideString(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK)
718 {
719 Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail);
720 return false;
721 }
a975e06e 722 }
723
724 UINT aFrameCount = 0, aFrameSizeX = 0, aFrameSizeY = 0;
725 WICPixelFormatGUID aWicPixelFormat = getNullGuid();
726 Image_ComPtr<IWICBitmapFrameDecode> aWicFrameDecode;
727 if (aWicDecoder->GetFrameCount (&aFrameCount) != S_OK
728 || aFrameCount < 1
729 || aWicDecoder->GetFrame (0, &aWicFrameDecode.ChangePtr()) != S_OK
730 || aWicFrameDecode->GetSize (&aFrameSizeX, &aFrameSizeY) != S_OK
731 || aWicFrameDecode->GetPixelFormat (&aWicPixelFormat))
732 {
733 Message::DefaultMessenger()->Send ("Error: cannot get WIC Image Frame", Message_Fail);
734 return false;
735 }
736
737 Image_ComPtr<IWICFormatConverter> aWicConvertedFrame;
738 Image_Format aPixelFormat = convertFromWicFormat (aWicPixelFormat);
739 if (aPixelFormat == Image_Format_UNKNOWN)
740 {
741 aPixelFormat = Image_Format_RGB;
742 if (aWicImgFactory->CreateFormatConverter (&aWicConvertedFrame.ChangePtr()) != S_OK
743 || aWicConvertedFrame->Initialize (aWicFrameDecode.get(), convertToWicFormat (aPixelFormat), WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom) != S_OK)
744 {
745 Message::DefaultMessenger()->Send ("Error: cannot convert WIC Image Frame to RGB format", Message_Fail);
746 return false;
747 }
748 aWicFrameDecode.Nullify();
749 }
750
751 if (!Image_PixMap::InitTrash (aPixelFormat, aFrameSizeX, aFrameSizeY))
752 {
753 Message::DefaultMessenger()->Send ("Error: cannot initialize memory for image", Message_Fail);
754 return false;
755 }
756
757 IWICBitmapSource* aWicSrc = aWicFrameDecode.get();
758 if(!aWicConvertedFrame.IsNull())
759 {
760 aWicSrc = aWicConvertedFrame.get();
761 }
762 if (aWicSrc->CopyPixels (NULL, (UINT )SizeRowBytes(), (UINT )SizeBytes(), ChangeData()) != S_OK)
763 {
764 Message::DefaultMessenger()->Send ("Error: cannot copy pixels from WIC Image", Message_Fail);
765 return false;
766 }
767 SetTopDown (true);
768 return true;
769}
88b12b7c 770bool Image_AlienPixMap::Load (std::istream& theStream,
771 const TCollection_AsciiString& theFilePath)
772{
773 Clear();
774
775 // fallback copying stream data into transient buffer
776 const std::streamoff aStart = theStream.tellg();
777 theStream.seekg (0, std::ios::end);
778 const Standard_Integer aLen = Standard_Integer(theStream.tellg() - aStart);
779 theStream.seekg (aStart);
780 if (aLen <= 0)
781 {
782 Message::DefaultMessenger()->Send ("Error: empty stream", Message_Fail);
783 return false;
784 }
785
786 NCollection_Array1<Standard_Byte> aBuff (1, aLen);
787 if (!theStream.read ((char* )&aBuff.ChangeFirst(), aBuff.Size()))
788 {
789 Message::DefaultMessenger()->Send ("Error: unable to read stream", Message_Fail);
790 return false;
791 }
792
793 return Load (&aBuff.ChangeFirst(), aBuff.Size(), theFilePath);
794}
692613e5 795#else
88b12b7c 796bool Image_AlienPixMap::Load (std::istream& ,
797 const TCollection_AsciiString& )
798{
799 Clear();
800 Message::DefaultMessenger()->Send ("Error: no image library available", Message_Fail);
801 return false;
802}
803bool Image_AlienPixMap::Load (const Standard_Byte* ,
804 Standard_Size ,
805 const TCollection_AsciiString& )
35e08fe8 806{
807 Clear();
88b12b7c 808 Message::DefaultMessenger()->Send ("Error: no image library available", Message_Fail);
692613e5 809 return false;
692613e5 810}
35e08fe8 811#endif
692613e5 812
813// =======================================================================
814// function : savePPM
815// purpose :
816// =======================================================================
817bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const
818{
819 if (IsEmpty())
820 {
821 return false;
822 }
823
824 // Open file
94708556 825 FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb");
692613e5 826 if (aFile == NULL)
827 {
828 return false;
829 }
830
831 // Write header
832 fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY());
833 fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n");
834
835 // Write pixel data
692613e5 836 Standard_Byte aByte;
837 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
838 {
a7b491fc 839 for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
692613e5 840 {
841 // extremely SLOW but universal (implemented for all supported pixel formats)
e958a649 842 const Quantity_ColorRGBA aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow);
843 aByte = Standard_Byte(aColor.GetRGB().Red() * 255.0); fwrite (&aByte, 1, 1, aFile);
844 aByte = Standard_Byte(aColor.GetRGB().Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
845 aByte = Standard_Byte(aColor.GetRGB().Blue() * 255.0); fwrite (&aByte, 1, 1, aFile);
692613e5 846 }
847 }
848
849 // Close file
850 fclose (aFile);
851 return true;
852}
853
854// =======================================================================
855// function : Save
856// purpose :
857// =======================================================================
858bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName)
859{
860#ifdef HAVE_FREEIMAGE
861 if (myLibImage == NULL)
862 {
863 return false;
864 }
865
7aa1b65c 866#ifdef _WIN32
867 const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True);
fb0b0531 868 FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU (aFileNameW.ToWideString());
7aa1b65c 869#else
692613e5 870 FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString());
7aa1b65c 871#endif
692613e5 872 if (anImageFormat == FIF_UNKNOWN)
873 {
0797d9d3 874#ifdef OCCT_DEBUG
692613e5 875 std::cerr << "Image_PixMap, image format doesn't supported!\n";
63c629aa 876#endif
692613e5 877 return false;
878 }
879
880 if (IsTopDown())
881 {
882 FreeImage_FlipVertical (myLibImage);
883 SetTopDown (false);
884 }
885
dc858f4c 886 // FreeImage doesn't provide flexible format conversion API
887 // so we should perform multiple conversions in some cases!
692613e5 888 FIBITMAP* anImageToDump = myLibImage;
889 switch (anImageFormat)
890 {
891 case FIF_PNG:
892 case FIF_BMP:
893 {
dc858f4c 894 if (Format() == Image_Format_BGR32
895 || Format() == Image_Format_RGB32)
692613e5 896 {
897 // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
692613e5 898 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
899 {
900 for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
901 {
ca0c0b11 902 myData.ChangeValue (aRow, aCol)[3] = 0xFF;
692613e5 903 }
904 }
905 }
906 else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
907 {
908 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
909 }
910 break;
911 }
912 case FIF_GIF:
913 {
914 FIBITMAP* aTmpBitmap = myLibImage;
915 if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
916 {
917 aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
918 if (aTmpBitmap == NULL)
919 {
920 return false;
921 }
922 }
923
924 if (FreeImage_GetBPP (aTmpBitmap) != 24)
925 {
926 FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
927 if (aTmpBitmap != myLibImage)
928 {
929 FreeImage_Unload (aTmpBitmap);
930 }
931 if (aTmpBitmap24 == NULL)
932 {
933 return false;
934 }
935 aTmpBitmap = aTmpBitmap24;
936 }
937
dc858f4c 938 // need conversion to image with palette (requires 24bit bitmap)
692613e5 939 anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
940 if (aTmpBitmap != myLibImage)
941 {
942 FreeImage_Unload (aTmpBitmap);
943 }
944 break;
945 }
38d90bb3 946 case FIF_HDR:
692613e5 947 case FIF_EXR:
948 {
dc858f4c 949 if (Format() == Image_Format_Gray
950 || Format() == Image_Format_Alpha)
692613e5 951 {
952 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
953 }
dc858f4c 954 else if (Format() == Image_Format_RGBA
955 || Format() == Image_Format_BGRA)
692613e5 956 {
957 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
958 }
959 else
960 {
961 FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
962 if (aImgTypeFI != FIT_RGBF
963 && aImgTypeFI != FIT_RGBAF
964 && aImgTypeFI != FIT_FLOAT)
965 {
966 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
967 }
968 }
969 break;
970 }
971 default:
972 {
973 if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
974 {
975 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
976 if (anImageToDump == NULL)
977 {
978 return false;
979 }
980 }
981
982 if (FreeImage_GetBPP (anImageToDump) != 24)
983 {
984 FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
985 if (anImageToDump != myLibImage)
986 {
987 FreeImage_Unload (anImageToDump);
988 }
989 if (aTmpBitmap24 == NULL)
990 {
991 return false;
992 }
993 anImageToDump = aTmpBitmap24;
994 }
995 break;
996 }
997 }
998
999 if (anImageToDump == NULL)
1000 {
1001 return false;
1002 }
1003
7aa1b65c 1004#ifdef _WIN32
fb0b0531 1005 bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString()) != FALSE);
7aa1b65c 1006#else
1007 bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE);
1008#endif
692613e5 1009 if (anImageToDump != myLibImage)
1010 {
1011 FreeImage_Unload (anImageToDump);
1012 }
1013 return isSaved;
a975e06e 1014
1015#elif defined(HAVE_WINCODEC)
1016
1017 TCollection_AsciiString aFileNameLower = theFileName;
1018 aFileNameLower.LowerCase();
1019 GUID aFileFormat = getNullGuid();
1020 if (aFileNameLower.EndsWith (".ppm"))
1021 {
1022 return savePPM (theFileName);
1023 }
1024 else if (aFileNameLower.EndsWith (".bmp"))
1025 {
1026 aFileFormat = GUID_ContainerFormatBmp;
1027 }
1028 else if (aFileNameLower.EndsWith (".png"))
1029 {
1030 aFileFormat = GUID_ContainerFormatPng;
1031 }
1032 else if (aFileNameLower.EndsWith (".jpg")
1033 || aFileNameLower.EndsWith (".jpeg"))
1034 {
1035 aFileFormat = GUID_ContainerFormatJpeg;
1036 }
1037 else if (aFileNameLower.EndsWith (".tiff"))
1038 {
1039 aFileFormat = GUID_ContainerFormatTiff;
1040 }
1041 else if (aFileNameLower.EndsWith (".gif"))
1042 {
1043 aFileFormat = GUID_ContainerFormatGif;
1044 }
1045
1046 if (aFileFormat == getNullGuid())
1047 {
1048 Message::DefaultMessenger()->Send ("Error: unsupported image format", Message_Fail);
1049 return false;
1050 }
1051
88b12b7c 1052 Image_ComPtr<IWICImagingFactory> aWicImgFactory;
a975e06e 1053 CoInitializeEx (NULL, COINIT_MULTITHREADED);
88b12b7c 1054 if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK)
a975e06e 1055 {
1056 Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail);
1057 return false;
1058 }
1059
1060 Image_ComPtr<IWICStream> aWicFileStream;
1061 Image_ComPtr<IWICBitmapEncoder> aWicEncoder;
1062 const TCollection_ExtendedString aFileNameW (theFileName);
1063 if (aWicImgFactory->CreateStream (&aWicFileStream.ChangePtr()) != S_OK
1064 || aWicFileStream->InitializeFromFilename (aFileNameW.ToWideString(), GENERIC_WRITE) != S_OK)
1065 {
1066 Message::DefaultMessenger()->Send ("Error: cannot create WIC File Stream", Message_Fail);
1067 return false;
1068 }
1069 if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK
1070 || aWicEncoder->Initialize (aWicFileStream.get(), WICBitmapEncoderNoCache) != S_OK)
1071 {
1072 Message::DefaultMessenger()->Send ("Error: cannot create WIC Encoder", Message_Fail);
1073 return false;
1074 }
1075
1076 const WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat);
1077 if (aWicPixelFormat == getNullGuid())
1078 {
1079 Message::DefaultMessenger()->Send ("Error: unsupported pixel format", Message_Fail);
1080 return false;
1081 }
1082
1083 WICPixelFormatGUID aWicPixelFormatRes = aWicPixelFormat;
1084 Image_ComPtr<IWICBitmapFrameEncode> aWicFrameEncode;
1085 if (aWicEncoder->CreateNewFrame (&aWicFrameEncode.ChangePtr(), NULL) != S_OK
1086 || aWicFrameEncode->Initialize (NULL) != S_OK
1087 || aWicFrameEncode->SetSize ((UINT )SizeX(), (UINT )SizeY()) != S_OK
1088 || aWicFrameEncode->SetPixelFormat (&aWicPixelFormatRes) != S_OK)
1089 {
1090 Message::DefaultMessenger()->Send ("Error: cannot create WIC Frame", Message_Fail);
1091 return false;
1092 }
1093
1094 if (aWicPixelFormatRes != aWicPixelFormat)
1095 {
1096 Message::DefaultMessenger()->Send ("Error: pixel format is unsupported by image format", Message_Fail);
1097 return false;
1098 }
1099
1100 if (IsTopDown())
1101 {
1102 if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )Data()) != S_OK)
1103 {
1104 Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail);
1105 return false;
1106 }
1107 }
1108 else
1109 {
1110 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
1111 {
1112 if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )Row (aRow)) != S_OK)
1113 {
1114 Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail);
1115 return false;
1116 }
1117 }
1118 }
1119
1120 if (aWicFrameEncode->Commit() != S_OK
1121 || aWicEncoder->Commit() != S_OK)
1122 {
1123 Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC Frame", Message_Fail);
1124 return false;
1125 }
1126 if (aWicFileStream->Commit (STGC_DEFAULT) != S_OK)
1127 {
1128 //Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC File Stream", Message_Fail);
1129 //return false;
1130 }
1131 return true;
692613e5 1132#else
1133 const Standard_Integer aLen = theFileName.Length();
1134 if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
29cb310a 1135 && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 )
692613e5 1136 {
1137 return savePPM (theFileName);
1138 }
0797d9d3 1139#ifdef OCCT_DEBUG
692613e5 1140 std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n";
63c629aa 1141#endif
692613e5 1142 return savePPM (theFileName);
1143#endif
1144}
1145
1146// =======================================================================
1147// function : AdjustGamma
1148// purpose :
1149// =======================================================================
7aa1b65c 1150bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr)
692613e5 1151{
7aa1b65c 1152#ifdef HAVE_FREEIMAGE
692613e5 1153 return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE;
1154#else
7aa1b65c 1155 (void )theGammaCorr;
1156 return false;
35e08fe8 1157#endif
7aa1b65c 1158}