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) |
27 | //#include <initguid.h> |
28 | #include <wincodec.h> |
29 | #undef min |
30 | #undef max |
692613e5 |
31 | #endif |
32 | |
33 | #include <Image_AlienPixMap.hxx> |
34 | #include <gp.hxx> |
0c015ee2 |
35 | #include <Message.hxx> |
36 | #include <Message_Messenger.hxx> |
692613e5 |
37 | #include <TCollection_AsciiString.hxx> |
7aa1b65c |
38 | #include <TCollection_ExtendedString.hxx> |
94708556 |
39 | #include <OSD_OpenFile.hxx> |
692613e5 |
40 | #include <fstream> |
a096a7a5 |
41 | #include <algorithm> |
692613e5 |
42 | |
f5f4ebd0 |
43 | IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap,Image_PixMap) |
44 | |
692613e5 |
45 | namespace |
46 | { |
a975e06e |
47 | #ifdef HAVE_FREEIMAGE |
dc858f4c |
48 | static Image_Format convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI, |
49 | FREE_IMAGE_COLOR_TYPE theColorTypeFI, |
50 | unsigned theBitsPerPixel) |
692613e5 |
51 | { |
52 | switch (theFormatFI) |
53 | { |
dc858f4c |
54 | case FIT_RGBF: return Image_Format_RGBF; |
55 | case FIT_RGBAF: return Image_Format_RGBAF; |
56 | case FIT_FLOAT: return Image_Format_GrayF; |
692613e5 |
57 | case FIT_BITMAP: |
58 | { |
59 | switch (theColorTypeFI) |
60 | { |
61 | case FIC_MINISBLACK: |
62 | { |
dc858f4c |
63 | return Image_Format_Gray; |
692613e5 |
64 | } |
65 | case FIC_RGB: |
66 | { |
67 | if (Image_PixMap::IsBigEndianHost()) |
68 | { |
dc858f4c |
69 | return (theBitsPerPixel == 32) ? Image_Format_RGB32 : Image_Format_RGB; |
692613e5 |
70 | } |
71 | else |
72 | { |
dc858f4c |
73 | return (theBitsPerPixel == 32) ? Image_Format_BGR32 : Image_Format_BGR; |
692613e5 |
74 | } |
75 | } |
76 | case FIC_RGBALPHA: |
77 | { |
dc858f4c |
78 | return Image_PixMap::IsBigEndianHost() ? Image_Format_RGBA : Image_Format_BGRA; |
692613e5 |
79 | } |
80 | default: |
dc858f4c |
81 | return Image_Format_UNKNOWN; |
692613e5 |
82 | } |
83 | } |
84 | default: |
dc858f4c |
85 | return Image_Format_UNKNOWN; |
692613e5 |
86 | } |
87 | } |
88 | |
dc858f4c |
89 | static FREE_IMAGE_TYPE convertToFreeFormat (Image_Format theFormat) |
692613e5 |
90 | { |
91 | switch (theFormat) |
92 | { |
dc858f4c |
93 | case Image_Format_GrayF: |
94 | case Image_Format_AlphaF: |
692613e5 |
95 | return FIT_FLOAT; |
dc858f4c |
96 | case Image_Format_RGBAF: |
692613e5 |
97 | return FIT_RGBAF; |
dc858f4c |
98 | case Image_Format_RGBF: |
692613e5 |
99 | return FIT_RGBF; |
dc858f4c |
100 | case Image_Format_RGBA: |
101 | case Image_Format_BGRA: |
102 | case Image_Format_RGB32: |
103 | case Image_Format_BGR32: |
104 | case Image_Format_RGB: |
105 | case Image_Format_BGR: |
106 | case Image_Format_Gray: |
107 | case Image_Format_Alpha: |
692613e5 |
108 | return FIT_BITMAP; |
109 | default: |
110 | return FIT_UNKNOWN; |
111 | } |
112 | } |
a975e06e |
113 | #elif defined(HAVE_WINCODEC) |
692613e5 |
114 | |
a975e06e |
115 | //! Return a zero GUID |
116 | static GUID getNullGuid() |
117 | { |
118 | GUID aGuid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }; |
119 | return aGuid; |
120 | } |
121 | |
122 | //! Sentry over IUnknown pointer. |
123 | template<class T> class Image_ComPtr |
124 | { |
125 | public: |
126 | //! Empty constructor. |
127 | Image_ComPtr() |
128 | : myPtr (NULL) {} |
129 | |
130 | //! Destructor. |
131 | ~Image_ComPtr() |
132 | { |
133 | Nullify(); |
134 | } |
135 | |
136 | //! Return TRUE if pointer is NULL. |
137 | bool IsNull() const { return myPtr == NULL; } |
138 | |
139 | //! Release the pointer. |
140 | void Nullify() |
141 | { |
142 | if (myPtr != NULL) |
143 | { |
144 | myPtr->Release(); |
145 | myPtr = NULL; |
146 | } |
147 | } |
148 | |
149 | //! Return pointer for initialization. |
150 | T*& ChangePtr() |
151 | { |
152 | Standard_ASSERT_RAISE (myPtr == NULL, "Pointer cannot be initialized twice!"); |
153 | return myPtr; |
154 | } |
155 | |
156 | //! Return pointer. |
157 | T* get() { return myPtr; } |
158 | |
159 | //! Return pointer. |
160 | T* operator->() { return get(); } |
161 | |
162 | //! Cast handle to contained type |
163 | T& operator*() { return *get(); } |
164 | |
165 | private: |
166 | T* myPtr; |
167 | }; |
168 | |
169 | //! Convert WIC GUID to Image_Format. |
170 | static Image_Format convertFromWicFormat (const WICPixelFormatGUID& theFormat) |
171 | { |
172 | if (theFormat == GUID_WICPixelFormat32bppBGRA) |
173 | { |
174 | return Image_Format_BGRA; |
175 | } |
176 | else if (theFormat == GUID_WICPixelFormat32bppBGR) |
177 | { |
178 | return Image_Format_BGR32; |
179 | } |
180 | else if (theFormat == GUID_WICPixelFormat24bppRGB) |
181 | { |
182 | return Image_Format_RGB; |
183 | } |
184 | else if (theFormat == GUID_WICPixelFormat24bppBGR) |
185 | { |
186 | return Image_Format_BGR; |
187 | } |
188 | else if (theFormat == GUID_WICPixelFormat8bppGray) |
189 | { |
190 | return Image_Format_Gray; |
191 | } |
192 | return Image_Format_UNKNOWN; |
193 | } |
194 | |
195 | //! Convert Image_Format to WIC GUID. |
196 | static WICPixelFormatGUID convertToWicFormat (Image_Format theFormat) |
197 | { |
198 | switch (theFormat) |
199 | { |
200 | case Image_Format_BGRA: return GUID_WICPixelFormat32bppBGRA; |
201 | case Image_Format_BGR32: return GUID_WICPixelFormat32bppBGR; |
202 | case Image_Format_RGB: return GUID_WICPixelFormat24bppRGB; |
203 | case Image_Format_BGR: return GUID_WICPixelFormat24bppBGR; |
204 | case Image_Format_Gray: return GUID_WICPixelFormat8bppGray; |
205 | case Image_Format_Alpha: return GUID_WICPixelFormat8bppGray; // GUID_WICPixelFormat8bppAlpha |
206 | case Image_Format_GrayF: // GUID_WICPixelFormat32bppGrayFloat |
207 | case Image_Format_AlphaF: |
208 | case Image_Format_RGBAF: // GUID_WICPixelFormat128bppRGBAFloat |
209 | case Image_Format_RGBF: // GUID_WICPixelFormat96bppRGBFloat |
210 | case Image_Format_RGBA: // GUID_WICPixelFormat32bppRGBA |
211 | case Image_Format_RGB32: // GUID_WICPixelFormat32bppRGB |
212 | default: |
213 | return getNullGuid(); |
214 | } |
215 | } |
216 | |
217 | #endif |
218 | } |
692613e5 |
219 | |
220 | // ======================================================================= |
221 | // function : Image_AlienPixMap |
222 | // purpose : |
223 | // ======================================================================= |
224 | Image_AlienPixMap::Image_AlienPixMap() |
225 | : myLibImage (NULL) |
226 | { |
227 | SetTopDown (false); |
228 | } |
229 | |
230 | // ======================================================================= |
231 | // function : ~Image_AlienPixMap |
232 | // purpose : |
233 | // ======================================================================= |
234 | Image_AlienPixMap::~Image_AlienPixMap() |
235 | { |
236 | Clear(); |
237 | } |
238 | |
239 | // ======================================================================= |
240 | // function : InitWrapper |
241 | // purpose : |
242 | // ======================================================================= |
dc858f4c |
243 | bool Image_AlienPixMap::InitWrapper (Image_Format, |
35e08fe8 |
244 | Standard_Byte*, |
245 | const Standard_Size, |
246 | const Standard_Size, |
247 | const Standard_Size) |
692613e5 |
248 | { |
249 | Clear(); |
250 | return false; |
251 | } |
252 | |
253 | // ======================================================================= |
254 | // function : InitTrash |
255 | // purpose : |
256 | // ======================================================================= |
498ce76b |
257 | #ifdef HAVE_FREEIMAGE |
dc858f4c |
258 | bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat, |
692613e5 |
259 | const Standard_Size theSizeX, |
260 | const Standard_Size theSizeY, |
498ce76b |
261 | const Standard_Size /*theSizeRowBytes*/) |
692613e5 |
262 | { |
263 | Clear(); |
692613e5 |
264 | FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat); |
265 | int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8; |
266 | if (aFormatFI == FIT_UNKNOWN) |
267 | { |
268 | aFormatFI = FIT_BITMAP; |
269 | aBitsPerPixel = 24; |
270 | } |
271 | |
272 | FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel); |
dc858f4c |
273 | Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage), |
274 | FreeImage_GetColorType(anImage), |
275 | FreeImage_GetBPP (anImage)); |
276 | if (thePixelFormat == Image_Format_BGR32 |
277 | || thePixelFormat == Image_Format_RGB32) |
692613e5 |
278 | { |
279 | //FreeImage_SetTransparent (anImage, FALSE); |
dc858f4c |
280 | aFormat = (aFormat == Image_Format_BGRA) ? Image_Format_BGR32 : Image_Format_RGB32; |
692613e5 |
281 | } |
282 | |
283 | Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage), |
284 | FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); |
285 | SetTopDown (false); |
286 | |
287 | // assign image after wrapper initialization (virtual Clear() called inside) |
288 | myLibImage = anImage; |
289 | return true; |
498ce76b |
290 | } |
a975e06e |
291 | #elif defined(HAVE_WINCODEC) |
292 | bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat, |
293 | const Standard_Size theSizeX, |
294 | const Standard_Size theSizeY, |
295 | const Standard_Size theSizeRowBytes) |
296 | { |
297 | Clear(); |
298 | Image_Format aFormat = thePixelFormat; |
299 | switch (aFormat) |
300 | { |
301 | case Image_Format_RGB: |
302 | aFormat = Image_Format_BGR; |
303 | break; |
304 | case Image_Format_RGB32: |
305 | aFormat = Image_Format_BGR32; |
306 | break; |
307 | case Image_Format_RGBA: |
308 | aFormat = Image_Format_BGRA; |
309 | break; |
310 | default: |
311 | break; |
312 | } |
313 | |
314 | if (!Image_PixMap::InitTrash (aFormat, theSizeX, theSizeY, theSizeRowBytes)) |
315 | { |
316 | return false; |
317 | } |
318 | SetTopDown (true); |
319 | return true; |
320 | } |
692613e5 |
321 | #else |
dc858f4c |
322 | bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat, |
498ce76b |
323 | const Standard_Size theSizeX, |
324 | const Standard_Size theSizeY, |
325 | const Standard_Size theSizeRowBytes) |
326 | { |
692613e5 |
327 | return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes); |
692613e5 |
328 | } |
498ce76b |
329 | #endif |
692613e5 |
330 | |
331 | // ======================================================================= |
3c3131a0 |
332 | // function : InitCopy |
692613e5 |
333 | // purpose : |
334 | // ======================================================================= |
335 | bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy) |
336 | { |
337 | if (&theCopy == this) |
338 | { |
339 | // self-copying disallowed |
340 | return false; |
341 | } |
342 | if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes())) |
343 | { |
344 | return false; |
345 | } |
346 | |
347 | if (myImgFormat == theCopy.Format()) |
348 | { |
ca0c0b11 |
349 | if (SizeRowBytes() == theCopy.SizeRowBytes() |
350 | && TopDownInc() == theCopy.TopDownInc()) |
692613e5 |
351 | { |
352 | // copy with one call |
ca0c0b11 |
353 | memcpy (ChangeData(), theCopy.Data(), std::min (SizeBytes(), theCopy.SizeBytes())); |
692613e5 |
354 | return true; |
355 | } |
356 | |
357 | // copy row-by-row |
ca0c0b11 |
358 | const Standard_Size aRowSizeBytes = std::min (SizeRowBytes(), theCopy.SizeRowBytes()); |
359 | for (Standard_Size aRow = 0; aRow < myData.SizeY; ++aRow) |
692613e5 |
360 | { |
361 | memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes); |
362 | } |
363 | return true; |
364 | } |
365 | |
366 | // pixel format conversion required |
367 | Clear(); |
368 | return false; |
369 | } |
370 | |
371 | // ======================================================================= |
372 | // function : Clear |
373 | // purpose : |
374 | // ======================================================================= |
ca0c0b11 |
375 | void Image_AlienPixMap::Clear() |
692613e5 |
376 | { |
ca0c0b11 |
377 | Image_PixMap::Clear(); |
692613e5 |
378 | #ifdef HAVE_FREEIMAGE |
379 | if (myLibImage != NULL) |
380 | { |
381 | FreeImage_Unload (myLibImage); |
382 | myLibImage = NULL; |
383 | } |
384 | #endif |
385 | } |
386 | |
387 | // ======================================================================= |
388 | // function : Load |
389 | // purpose : |
390 | // ======================================================================= |
35e08fe8 |
391 | #ifdef HAVE_FREEIMAGE |
692613e5 |
392 | bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath) |
393 | { |
394 | Clear(); |
7aa1b65c |
395 | |
396 | #ifdef _WIN32 |
a975e06e |
397 | const TCollection_ExtendedString aFileNameW (theImagePath); |
fb0b0531 |
398 | FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeU (aFileNameW.ToWideString(), 0); |
7aa1b65c |
399 | #else |
692613e5 |
400 | FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0); |
7aa1b65c |
401 | #endif |
692613e5 |
402 | if (aFIF == FIF_UNKNOWN) |
403 | { |
404 | // no signature? try to guess the file format from the file extension |
405 | aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString()); |
406 | } |
407 | if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF)) |
408 | { |
0c015ee2 |
409 | TCollection_AsciiString aMessage = "Error: image file '"; |
410 | aMessage.AssignCat (theImagePath); |
411 | aMessage.AssignCat ("' has unsupported file format."); |
412 | ::Message::DefaultMessenger()->Send (aMessage, Message_Fail); |
692613e5 |
413 | return false; |
414 | } |
415 | |
416 | int aLoadFlags = 0; |
417 | if (aFIF == FIF_GIF) |
418 | { |
419 | // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading |
420 | aLoadFlags = GIF_PLAYBACK; |
421 | } |
422 | else if (aFIF == FIF_ICO) |
423 | { |
424 | // convert to 32bpp and create an alpha channel from the AND-mask when loading |
425 | aLoadFlags = ICO_MAKEALPHA; |
426 | } |
427 | |
7aa1b65c |
428 | #ifdef _WIN32 |
fb0b0531 |
429 | FIBITMAP* anImage = FreeImage_LoadU (aFIF, aFileNameW.ToWideString(), aLoadFlags); |
7aa1b65c |
430 | #else |
431 | FIBITMAP* anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags); |
432 | #endif |
692613e5 |
433 | if (anImage == NULL) |
434 | { |
0c015ee2 |
435 | TCollection_AsciiString aMessage = "Error: image file '"; |
436 | aMessage.AssignCat (theImagePath); |
437 | aMessage.AssignCat ("' is missing or invalid."); |
438 | ::Message::DefaultMessenger()->Send (aMessage, Message_Fail); |
692613e5 |
439 | return false; |
440 | } |
441 | |
dc858f4c |
442 | Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage), |
443 | FreeImage_GetColorType(anImage), |
444 | FreeImage_GetBPP (anImage)); |
445 | if (aFormat == Image_Format_UNKNOWN) |
692613e5 |
446 | { |
447 | //anImage = FreeImage_ConvertTo24Bits (anImage); |
0c015ee2 |
448 | TCollection_AsciiString aMessage = "Error: image file '"; |
449 | aMessage.AssignCat (theImagePath); |
450 | aMessage.AssignCat ("' has unsupported pixel format."); |
451 | ::Message::DefaultMessenger()->Send (aMessage, Message_Fail); |
692613e5 |
452 | return false; |
453 | } |
454 | |
455 | Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage), |
456 | FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); |
457 | SetTopDown (false); |
458 | |
459 | // assign image after wrapper initialization (virtual Clear() called inside) |
460 | myLibImage = anImage; |
461 | return true; |
35e08fe8 |
462 | } |
a975e06e |
463 | #elif defined(HAVE_WINCODEC) |
464 | bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath) |
465 | { |
466 | Clear(); |
467 | |
468 | IWICImagingFactory* aWicImgFactory = NULL; |
469 | CoInitializeEx (NULL, COINIT_MULTITHREADED); |
470 | if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory)) != S_OK) |
471 | { |
472 | Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail); |
473 | return false; |
474 | } |
475 | |
476 | Image_ComPtr<IWICBitmapDecoder> aWicDecoder; |
477 | const TCollection_ExtendedString aFileNameW (theImagePath); |
478 | if (aWicImgFactory->CreateDecoderFromFilename (aFileNameW.ToWideString(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &aWicDecoder.ChangePtr()) != S_OK) |
479 | { |
480 | Message::DefaultMessenger()->Send ("Error: cannot create WIC Image Decoder", Message_Fail); |
481 | return false; |
482 | } |
483 | |
484 | UINT aFrameCount = 0, aFrameSizeX = 0, aFrameSizeY = 0; |
485 | WICPixelFormatGUID aWicPixelFormat = getNullGuid(); |
486 | Image_ComPtr<IWICBitmapFrameDecode> aWicFrameDecode; |
487 | if (aWicDecoder->GetFrameCount (&aFrameCount) != S_OK |
488 | || aFrameCount < 1 |
489 | || aWicDecoder->GetFrame (0, &aWicFrameDecode.ChangePtr()) != S_OK |
490 | || aWicFrameDecode->GetSize (&aFrameSizeX, &aFrameSizeY) != S_OK |
491 | || aWicFrameDecode->GetPixelFormat (&aWicPixelFormat)) |
492 | { |
493 | Message::DefaultMessenger()->Send ("Error: cannot get WIC Image Frame", Message_Fail); |
494 | return false; |
495 | } |
496 | |
497 | Image_ComPtr<IWICFormatConverter> aWicConvertedFrame; |
498 | Image_Format aPixelFormat = convertFromWicFormat (aWicPixelFormat); |
499 | if (aPixelFormat == Image_Format_UNKNOWN) |
500 | { |
501 | aPixelFormat = Image_Format_RGB; |
502 | if (aWicImgFactory->CreateFormatConverter (&aWicConvertedFrame.ChangePtr()) != S_OK |
503 | || aWicConvertedFrame->Initialize (aWicFrameDecode.get(), convertToWicFormat (aPixelFormat), WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom) != S_OK) |
504 | { |
505 | Message::DefaultMessenger()->Send ("Error: cannot convert WIC Image Frame to RGB format", Message_Fail); |
506 | return false; |
507 | } |
508 | aWicFrameDecode.Nullify(); |
509 | } |
510 | |
511 | if (!Image_PixMap::InitTrash (aPixelFormat, aFrameSizeX, aFrameSizeY)) |
512 | { |
513 | Message::DefaultMessenger()->Send ("Error: cannot initialize memory for image", Message_Fail); |
514 | return false; |
515 | } |
516 | |
517 | IWICBitmapSource* aWicSrc = aWicFrameDecode.get(); |
518 | if(!aWicConvertedFrame.IsNull()) |
519 | { |
520 | aWicSrc = aWicConvertedFrame.get(); |
521 | } |
522 | if (aWicSrc->CopyPixels (NULL, (UINT )SizeRowBytes(), (UINT )SizeBytes(), ChangeData()) != S_OK) |
523 | { |
524 | Message::DefaultMessenger()->Send ("Error: cannot copy pixels from WIC Image", Message_Fail); |
525 | return false; |
526 | } |
527 | SetTopDown (true); |
528 | return true; |
529 | } |
692613e5 |
530 | #else |
35e08fe8 |
531 | bool Image_AlienPixMap::Load (const TCollection_AsciiString&) |
532 | { |
533 | Clear(); |
692613e5 |
534 | return false; |
692613e5 |
535 | } |
35e08fe8 |
536 | #endif |
692613e5 |
537 | |
538 | // ======================================================================= |
539 | // function : savePPM |
540 | // purpose : |
541 | // ======================================================================= |
542 | bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const |
543 | { |
544 | if (IsEmpty()) |
545 | { |
546 | return false; |
547 | } |
548 | |
549 | // Open file |
94708556 |
550 | FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb"); |
692613e5 |
551 | if (aFile == NULL) |
552 | { |
553 | return false; |
554 | } |
555 | |
556 | // Write header |
557 | fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY()); |
558 | fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n"); |
559 | |
560 | // Write pixel data |
692613e5 |
561 | Standard_Byte aByte; |
562 | for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) |
563 | { |
a7b491fc |
564 | for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol) |
692613e5 |
565 | { |
566 | // extremely SLOW but universal (implemented for all supported pixel formats) |
e958a649 |
567 | const Quantity_ColorRGBA aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow); |
568 | aByte = Standard_Byte(aColor.GetRGB().Red() * 255.0); fwrite (&aByte, 1, 1, aFile); |
569 | aByte = Standard_Byte(aColor.GetRGB().Green() * 255.0); fwrite (&aByte, 1, 1, aFile); |
570 | aByte = Standard_Byte(aColor.GetRGB().Blue() * 255.0); fwrite (&aByte, 1, 1, aFile); |
692613e5 |
571 | } |
572 | } |
573 | |
574 | // Close file |
575 | fclose (aFile); |
576 | return true; |
577 | } |
578 | |
579 | // ======================================================================= |
580 | // function : Save |
581 | // purpose : |
582 | // ======================================================================= |
583 | bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName) |
584 | { |
585 | #ifdef HAVE_FREEIMAGE |
586 | if (myLibImage == NULL) |
587 | { |
588 | return false; |
589 | } |
590 | |
7aa1b65c |
591 | #ifdef _WIN32 |
592 | const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True); |
fb0b0531 |
593 | FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU (aFileNameW.ToWideString()); |
7aa1b65c |
594 | #else |
692613e5 |
595 | FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString()); |
7aa1b65c |
596 | #endif |
692613e5 |
597 | if (anImageFormat == FIF_UNKNOWN) |
598 | { |
0797d9d3 |
599 | #ifdef OCCT_DEBUG |
692613e5 |
600 | std::cerr << "Image_PixMap, image format doesn't supported!\n"; |
63c629aa |
601 | #endif |
692613e5 |
602 | return false; |
603 | } |
604 | |
605 | if (IsTopDown()) |
606 | { |
607 | FreeImage_FlipVertical (myLibImage); |
608 | SetTopDown (false); |
609 | } |
610 | |
dc858f4c |
611 | // FreeImage doesn't provide flexible format conversion API |
612 | // so we should perform multiple conversions in some cases! |
692613e5 |
613 | FIBITMAP* anImageToDump = myLibImage; |
614 | switch (anImageFormat) |
615 | { |
616 | case FIF_PNG: |
617 | case FIF_BMP: |
618 | { |
dc858f4c |
619 | if (Format() == Image_Format_BGR32 |
620 | || Format() == Image_Format_RGB32) |
692613e5 |
621 | { |
622 | // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF |
692613e5 |
623 | for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) |
624 | { |
625 | for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol) |
626 | { |
ca0c0b11 |
627 | myData.ChangeValue (aRow, aCol)[3] = 0xFF; |
692613e5 |
628 | } |
629 | } |
630 | } |
631 | else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) |
632 | { |
633 | anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); |
634 | } |
635 | break; |
636 | } |
637 | case FIF_GIF: |
638 | { |
639 | FIBITMAP* aTmpBitmap = myLibImage; |
640 | if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) |
641 | { |
642 | aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); |
643 | if (aTmpBitmap == NULL) |
644 | { |
645 | return false; |
646 | } |
647 | } |
648 | |
649 | if (FreeImage_GetBPP (aTmpBitmap) != 24) |
650 | { |
651 | FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap); |
652 | if (aTmpBitmap != myLibImage) |
653 | { |
654 | FreeImage_Unload (aTmpBitmap); |
655 | } |
656 | if (aTmpBitmap24 == NULL) |
657 | { |
658 | return false; |
659 | } |
660 | aTmpBitmap = aTmpBitmap24; |
661 | } |
662 | |
dc858f4c |
663 | // need conversion to image with palette (requires 24bit bitmap) |
692613e5 |
664 | anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT); |
665 | if (aTmpBitmap != myLibImage) |
666 | { |
667 | FreeImage_Unload (aTmpBitmap); |
668 | } |
669 | break; |
670 | } |
38d90bb3 |
671 | case FIF_HDR: |
692613e5 |
672 | case FIF_EXR: |
673 | { |
dc858f4c |
674 | if (Format() == Image_Format_Gray |
675 | || Format() == Image_Format_Alpha) |
692613e5 |
676 | { |
677 | anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT); |
678 | } |
dc858f4c |
679 | else if (Format() == Image_Format_RGBA |
680 | || Format() == Image_Format_BGRA) |
692613e5 |
681 | { |
682 | anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF); |
683 | } |
684 | else |
685 | { |
686 | FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage); |
687 | if (aImgTypeFI != FIT_RGBF |
688 | && aImgTypeFI != FIT_RGBAF |
689 | && aImgTypeFI != FIT_FLOAT) |
690 | { |
691 | anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF); |
692 | } |
693 | } |
694 | break; |
695 | } |
696 | default: |
697 | { |
698 | if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) |
699 | { |
700 | anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); |
701 | if (anImageToDump == NULL) |
702 | { |
703 | return false; |
704 | } |
705 | } |
706 | |
707 | if (FreeImage_GetBPP (anImageToDump) != 24) |
708 | { |
709 | FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump); |
710 | if (anImageToDump != myLibImage) |
711 | { |
712 | FreeImage_Unload (anImageToDump); |
713 | } |
714 | if (aTmpBitmap24 == NULL) |
715 | { |
716 | return false; |
717 | } |
718 | anImageToDump = aTmpBitmap24; |
719 | } |
720 | break; |
721 | } |
722 | } |
723 | |
724 | if (anImageToDump == NULL) |
725 | { |
726 | return false; |
727 | } |
728 | |
7aa1b65c |
729 | #ifdef _WIN32 |
fb0b0531 |
730 | bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString()) != FALSE); |
7aa1b65c |
731 | #else |
732 | bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE); |
733 | #endif |
692613e5 |
734 | if (anImageToDump != myLibImage) |
735 | { |
736 | FreeImage_Unload (anImageToDump); |
737 | } |
738 | return isSaved; |
a975e06e |
739 | |
740 | #elif defined(HAVE_WINCODEC) |
741 | |
742 | TCollection_AsciiString aFileNameLower = theFileName; |
743 | aFileNameLower.LowerCase(); |
744 | GUID aFileFormat = getNullGuid(); |
745 | if (aFileNameLower.EndsWith (".ppm")) |
746 | { |
747 | return savePPM (theFileName); |
748 | } |
749 | else if (aFileNameLower.EndsWith (".bmp")) |
750 | { |
751 | aFileFormat = GUID_ContainerFormatBmp; |
752 | } |
753 | else if (aFileNameLower.EndsWith (".png")) |
754 | { |
755 | aFileFormat = GUID_ContainerFormatPng; |
756 | } |
757 | else if (aFileNameLower.EndsWith (".jpg") |
758 | || aFileNameLower.EndsWith (".jpeg")) |
759 | { |
760 | aFileFormat = GUID_ContainerFormatJpeg; |
761 | } |
762 | else if (aFileNameLower.EndsWith (".tiff")) |
763 | { |
764 | aFileFormat = GUID_ContainerFormatTiff; |
765 | } |
766 | else if (aFileNameLower.EndsWith (".gif")) |
767 | { |
768 | aFileFormat = GUID_ContainerFormatGif; |
769 | } |
770 | |
771 | if (aFileFormat == getNullGuid()) |
772 | { |
773 | Message::DefaultMessenger()->Send ("Error: unsupported image format", Message_Fail); |
774 | return false; |
775 | } |
776 | |
777 | IWICImagingFactory* aWicImgFactory = NULL; |
778 | CoInitializeEx (NULL, COINIT_MULTITHREADED); |
779 | if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory)) != S_OK) |
780 | { |
781 | Message::DefaultMessenger()->Send ("Error: cannot initialize WIC Imaging Factory", Message_Fail); |
782 | return false; |
783 | } |
784 | |
785 | Image_ComPtr<IWICStream> aWicFileStream; |
786 | Image_ComPtr<IWICBitmapEncoder> aWicEncoder; |
787 | const TCollection_ExtendedString aFileNameW (theFileName); |
788 | if (aWicImgFactory->CreateStream (&aWicFileStream.ChangePtr()) != S_OK |
789 | || aWicFileStream->InitializeFromFilename (aFileNameW.ToWideString(), GENERIC_WRITE) != S_OK) |
790 | { |
791 | Message::DefaultMessenger()->Send ("Error: cannot create WIC File Stream", Message_Fail); |
792 | return false; |
793 | } |
794 | if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK |
795 | || aWicEncoder->Initialize (aWicFileStream.get(), WICBitmapEncoderNoCache) != S_OK) |
796 | { |
797 | Message::DefaultMessenger()->Send ("Error: cannot create WIC Encoder", Message_Fail); |
798 | return false; |
799 | } |
800 | |
801 | const WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat); |
802 | if (aWicPixelFormat == getNullGuid()) |
803 | { |
804 | Message::DefaultMessenger()->Send ("Error: unsupported pixel format", Message_Fail); |
805 | return false; |
806 | } |
807 | |
808 | WICPixelFormatGUID aWicPixelFormatRes = aWicPixelFormat; |
809 | Image_ComPtr<IWICBitmapFrameEncode> aWicFrameEncode; |
810 | if (aWicEncoder->CreateNewFrame (&aWicFrameEncode.ChangePtr(), NULL) != S_OK |
811 | || aWicFrameEncode->Initialize (NULL) != S_OK |
812 | || aWicFrameEncode->SetSize ((UINT )SizeX(), (UINT )SizeY()) != S_OK |
813 | || aWicFrameEncode->SetPixelFormat (&aWicPixelFormatRes) != S_OK) |
814 | { |
815 | Message::DefaultMessenger()->Send ("Error: cannot create WIC Frame", Message_Fail); |
816 | return false; |
817 | } |
818 | |
819 | if (aWicPixelFormatRes != aWicPixelFormat) |
820 | { |
821 | Message::DefaultMessenger()->Send ("Error: pixel format is unsupported by image format", Message_Fail); |
822 | return false; |
823 | } |
824 | |
825 | if (IsTopDown()) |
826 | { |
827 | if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )Data()) != S_OK) |
828 | { |
829 | Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail); |
830 | return false; |
831 | } |
832 | } |
833 | else |
834 | { |
835 | for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) |
836 | { |
837 | if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )Row (aRow)) != S_OK) |
838 | { |
839 | Message::DefaultMessenger()->Send ("Error: cannot write pixels to WIC Frame", Message_Fail); |
840 | return false; |
841 | } |
842 | } |
843 | } |
844 | |
845 | if (aWicFrameEncode->Commit() != S_OK |
846 | || aWicEncoder->Commit() != S_OK) |
847 | { |
848 | Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC Frame", Message_Fail); |
849 | return false; |
850 | } |
851 | if (aWicFileStream->Commit (STGC_DEFAULT) != S_OK) |
852 | { |
853 | //Message::DefaultMessenger()->Send ("Error: cannot commit data to WIC File Stream", Message_Fail); |
854 | //return false; |
855 | } |
856 | return true; |
692613e5 |
857 | #else |
858 | const Standard_Integer aLen = theFileName.Length(); |
859 | if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.') |
29cb310a |
860 | && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 ) |
692613e5 |
861 | { |
862 | return savePPM (theFileName); |
863 | } |
0797d9d3 |
864 | #ifdef OCCT_DEBUG |
692613e5 |
865 | std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n"; |
63c629aa |
866 | #endif |
692613e5 |
867 | return savePPM (theFileName); |
868 | #endif |
869 | } |
870 | |
871 | // ======================================================================= |
872 | // function : AdjustGamma |
873 | // purpose : |
874 | // ======================================================================= |
7aa1b65c |
875 | bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr) |
692613e5 |
876 | { |
7aa1b65c |
877 | #ifdef HAVE_FREEIMAGE |
692613e5 |
878 | return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE; |
879 | #else |
7aa1b65c |
880 | (void )theGammaCorr; |
881 | return false; |
35e08fe8 |
882 | #endif |
7aa1b65c |
883 | } |