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