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