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