0028441: Coding Rules - move out nested Image_PixMap::ImgFormat enumeration to dedica...
[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
692613e5 16#ifdef HAVE_FREEIMAGE
17 #include <FreeImage.h>
18
19 #ifdef _MSC_VER
20 #pragma comment( lib, "FreeImage.lib" )
21 #endif
22#endif
23
24#include <Image_AlienPixMap.hxx>
25#include <gp.hxx>
0c015ee2 26#include <Message.hxx>
27#include <Message_Messenger.hxx>
692613e5 28#include <TCollection_AsciiString.hxx>
7aa1b65c 29#include <TCollection_ExtendedString.hxx>
94708556 30#include <OSD_OpenFile.hxx>
692613e5 31#include <fstream>
a096a7a5 32#include <algorithm>
692613e5 33
f5f4ebd0 34IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap,Image_PixMap)
35
692613e5 36#ifdef HAVE_FREEIMAGE
37namespace
38{
dc858f4c 39 static Image_Format convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI,
40 FREE_IMAGE_COLOR_TYPE theColorTypeFI,
41 unsigned theBitsPerPixel)
692613e5 42 {
43 switch (theFormatFI)
44 {
dc858f4c 45 case FIT_RGBF: return Image_Format_RGBF;
46 case FIT_RGBAF: return Image_Format_RGBAF;
47 case FIT_FLOAT: return Image_Format_GrayF;
692613e5 48 case FIT_BITMAP:
49 {
50 switch (theColorTypeFI)
51 {
52 case FIC_MINISBLACK:
53 {
dc858f4c 54 return Image_Format_Gray;
692613e5 55 }
56 case FIC_RGB:
57 {
58 if (Image_PixMap::IsBigEndianHost())
59 {
dc858f4c 60 return (theBitsPerPixel == 32) ? Image_Format_RGB32 : Image_Format_RGB;
692613e5 61 }
62 else
63 {
dc858f4c 64 return (theBitsPerPixel == 32) ? Image_Format_BGR32 : Image_Format_BGR;
692613e5 65 }
66 }
67 case FIC_RGBALPHA:
68 {
dc858f4c 69 return Image_PixMap::IsBigEndianHost() ? Image_Format_RGBA : Image_Format_BGRA;
692613e5 70 }
71 default:
dc858f4c 72 return Image_Format_UNKNOWN;
692613e5 73 }
74 }
75 default:
dc858f4c 76 return Image_Format_UNKNOWN;
692613e5 77 }
78 }
79
dc858f4c 80 static FREE_IMAGE_TYPE convertToFreeFormat (Image_Format theFormat)
692613e5 81 {
82 switch (theFormat)
83 {
dc858f4c 84 case Image_Format_GrayF:
85 case Image_Format_AlphaF:
692613e5 86 return FIT_FLOAT;
dc858f4c 87 case Image_Format_RGBAF:
692613e5 88 return FIT_RGBAF;
dc858f4c 89 case Image_Format_RGBF:
692613e5 90 return FIT_RGBF;
dc858f4c 91 case Image_Format_RGBA:
92 case Image_Format_BGRA:
93 case Image_Format_RGB32:
94 case Image_Format_BGR32:
95 case Image_Format_RGB:
96 case Image_Format_BGR:
97 case Image_Format_Gray:
98 case Image_Format_Alpha:
692613e5 99 return FIT_BITMAP;
100 default:
101 return FIT_UNKNOWN;
102 }
103 }
68858c7d 104}
692613e5 105#endif
106
692613e5 107
108// =======================================================================
109// function : Image_AlienPixMap
110// purpose :
111// =======================================================================
112Image_AlienPixMap::Image_AlienPixMap()
113: myLibImage (NULL)
114{
115 SetTopDown (false);
116}
117
118// =======================================================================
119// function : ~Image_AlienPixMap
120// purpose :
121// =======================================================================
122Image_AlienPixMap::~Image_AlienPixMap()
123{
124 Clear();
125}
126
127// =======================================================================
128// function : InitWrapper
129// purpose :
130// =======================================================================
dc858f4c 131bool Image_AlienPixMap::InitWrapper (Image_Format,
35e08fe8 132 Standard_Byte*,
133 const Standard_Size,
134 const Standard_Size,
135 const Standard_Size)
692613e5 136{
137 Clear();
138 return false;
139}
140
141// =======================================================================
142// function : InitTrash
143// purpose :
144// =======================================================================
498ce76b 145#ifdef HAVE_FREEIMAGE
dc858f4c 146bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat,
692613e5 147 const Standard_Size theSizeX,
148 const Standard_Size theSizeY,
498ce76b 149 const Standard_Size /*theSizeRowBytes*/)
692613e5 150{
151 Clear();
692613e5 152 FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat);
153 int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8;
154 if (aFormatFI == FIT_UNKNOWN)
155 {
156 aFormatFI = FIT_BITMAP;
157 aBitsPerPixel = 24;
158 }
159
160 FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel);
dc858f4c 161 Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
162 FreeImage_GetColorType(anImage),
163 FreeImage_GetBPP (anImage));
164 if (thePixelFormat == Image_Format_BGR32
165 || thePixelFormat == Image_Format_RGB32)
692613e5 166 {
167 //FreeImage_SetTransparent (anImage, FALSE);
dc858f4c 168 aFormat = (aFormat == Image_Format_BGRA) ? Image_Format_BGR32 : Image_Format_RGB32;
692613e5 169 }
170
171 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
172 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
173 SetTopDown (false);
174
175 // assign image after wrapper initialization (virtual Clear() called inside)
176 myLibImage = anImage;
177 return true;
498ce76b 178}
692613e5 179#else
dc858f4c 180bool Image_AlienPixMap::InitTrash (Image_Format thePixelFormat,
498ce76b 181 const Standard_Size theSizeX,
182 const Standard_Size theSizeY,
183 const Standard_Size theSizeRowBytes)
184{
692613e5 185 return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes);
692613e5 186}
498ce76b 187#endif
692613e5 188
189// =======================================================================
3c3131a0 190// function : InitCopy
692613e5 191// purpose :
192// =======================================================================
193bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy)
194{
195 if (&theCopy == this)
196 {
197 // self-copying disallowed
198 return false;
199 }
200 if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes()))
201 {
202 return false;
203 }
204
205 if (myImgFormat == theCopy.Format())
206 {
ca0c0b11 207 if (SizeRowBytes() == theCopy.SizeRowBytes()
208 && TopDownInc() == theCopy.TopDownInc())
692613e5 209 {
210 // copy with one call
ca0c0b11 211 memcpy (ChangeData(), theCopy.Data(), std::min (SizeBytes(), theCopy.SizeBytes()));
692613e5 212 return true;
213 }
214
215 // copy row-by-row
ca0c0b11 216 const Standard_Size aRowSizeBytes = std::min (SizeRowBytes(), theCopy.SizeRowBytes());
217 for (Standard_Size aRow = 0; aRow < myData.SizeY; ++aRow)
692613e5 218 {
219 memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes);
220 }
221 return true;
222 }
223
224 // pixel format conversion required
225 Clear();
226 return false;
227}
228
229// =======================================================================
230// function : Clear
231// purpose :
232// =======================================================================
ca0c0b11 233void Image_AlienPixMap::Clear()
692613e5 234{
ca0c0b11 235 Image_PixMap::Clear();
692613e5 236#ifdef HAVE_FREEIMAGE
237 if (myLibImage != NULL)
238 {
239 FreeImage_Unload (myLibImage);
240 myLibImage = NULL;
241 }
242#endif
243}
244
245// =======================================================================
246// function : Load
247// purpose :
248// =======================================================================
35e08fe8 249#ifdef HAVE_FREEIMAGE
692613e5 250bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath)
251{
252 Clear();
7aa1b65c 253
254#ifdef _WIN32
255 const TCollection_ExtendedString aFileNameW (theImagePath.ToCString(), Standard_True);
fb0b0531 256 FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeU (aFileNameW.ToWideString(), 0);
7aa1b65c 257#else
692613e5 258 FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0);
7aa1b65c 259#endif
692613e5 260 if (aFIF == FIF_UNKNOWN)
261 {
262 // no signature? try to guess the file format from the file extension
263 aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString());
264 }
265 if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
266 {
0c015ee2 267 TCollection_AsciiString aMessage = "Error: image file '";
268 aMessage.AssignCat (theImagePath);
269 aMessage.AssignCat ("' has unsupported file format.");
270 ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
692613e5 271 return false;
272 }
273
274 int aLoadFlags = 0;
275 if (aFIF == FIF_GIF)
276 {
277 // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
278 aLoadFlags = GIF_PLAYBACK;
279 }
280 else if (aFIF == FIF_ICO)
281 {
282 // convert to 32bpp and create an alpha channel from the AND-mask when loading
283 aLoadFlags = ICO_MAKEALPHA;
284 }
285
7aa1b65c 286#ifdef _WIN32
fb0b0531 287 FIBITMAP* anImage = FreeImage_LoadU (aFIF, aFileNameW.ToWideString(), aLoadFlags);
7aa1b65c 288#else
289 FIBITMAP* anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags);
290#endif
692613e5 291 if (anImage == NULL)
292 {
0c015ee2 293 TCollection_AsciiString aMessage = "Error: image file '";
294 aMessage.AssignCat (theImagePath);
295 aMessage.AssignCat ("' is missing or invalid.");
296 ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
692613e5 297 return false;
298 }
299
dc858f4c 300 Image_Format aFormat = convertFromFreeFormat (FreeImage_GetImageType(anImage),
301 FreeImage_GetColorType(anImage),
302 FreeImage_GetBPP (anImage));
303 if (aFormat == Image_Format_UNKNOWN)
692613e5 304 {
305 //anImage = FreeImage_ConvertTo24Bits (anImage);
0c015ee2 306 TCollection_AsciiString aMessage = "Error: image file '";
307 aMessage.AssignCat (theImagePath);
308 aMessage.AssignCat ("' has unsupported pixel format.");
309 ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
692613e5 310 return false;
311 }
312
313 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
314 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
315 SetTopDown (false);
316
317 // assign image after wrapper initialization (virtual Clear() called inside)
318 myLibImage = anImage;
319 return true;
35e08fe8 320}
692613e5 321#else
35e08fe8 322bool Image_AlienPixMap::Load (const TCollection_AsciiString&)
323{
324 Clear();
692613e5 325 return false;
692613e5 326}
35e08fe8 327#endif
692613e5 328
329// =======================================================================
330// function : savePPM
331// purpose :
332// =======================================================================
333bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const
334{
335 if (IsEmpty())
336 {
337 return false;
338 }
339
340 // Open file
94708556 341 FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb");
692613e5 342 if (aFile == NULL)
343 {
344 return false;
345 }
346
347 // Write header
348 fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY());
349 fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n");
350
351 // Write pixel data
352 Quantity_Color aColor;
353 Quantity_Parameter aDummy;
354 Standard_Byte aByte;
355 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
356 {
a7b491fc 357 for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
692613e5 358 {
359 // extremely SLOW but universal (implemented for all supported pixel formats)
6a7d83c4 360 aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow, aDummy);
692613e5 361 aByte = Standard_Byte(aColor.Red() * 255.0); fwrite (&aByte, 1, 1, aFile);
362 aByte = Standard_Byte(aColor.Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
363 aByte = Standard_Byte(aColor.Blue() * 255.0); fwrite (&aByte, 1, 1, aFile);
364 }
365 }
366
367 // Close file
368 fclose (aFile);
369 return true;
370}
371
372// =======================================================================
373// function : Save
374// purpose :
375// =======================================================================
376bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName)
377{
378#ifdef HAVE_FREEIMAGE
379 if (myLibImage == NULL)
380 {
381 return false;
382 }
383
7aa1b65c 384#ifdef _WIN32
385 const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True);
fb0b0531 386 FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU (aFileNameW.ToWideString());
7aa1b65c 387#else
692613e5 388 FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString());
7aa1b65c 389#endif
692613e5 390 if (anImageFormat == FIF_UNKNOWN)
391 {
0797d9d3 392#ifdef OCCT_DEBUG
692613e5 393 std::cerr << "Image_PixMap, image format doesn't supported!\n";
63c629aa 394#endif
692613e5 395 return false;
396 }
397
398 if (IsTopDown())
399 {
400 FreeImage_FlipVertical (myLibImage);
401 SetTopDown (false);
402 }
403
dc858f4c 404 // FreeImage doesn't provide flexible format conversion API
405 // so we should perform multiple conversions in some cases!
692613e5 406 FIBITMAP* anImageToDump = myLibImage;
407 switch (anImageFormat)
408 {
409 case FIF_PNG:
410 case FIF_BMP:
411 {
dc858f4c 412 if (Format() == Image_Format_BGR32
413 || Format() == Image_Format_RGB32)
692613e5 414 {
415 // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
692613e5 416 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
417 {
418 for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
419 {
ca0c0b11 420 myData.ChangeValue (aRow, aCol)[3] = 0xFF;
692613e5 421 }
422 }
423 }
424 else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
425 {
426 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
427 }
428 break;
429 }
430 case FIF_GIF:
431 {
432 FIBITMAP* aTmpBitmap = myLibImage;
433 if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
434 {
435 aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
436 if (aTmpBitmap == NULL)
437 {
438 return false;
439 }
440 }
441
442 if (FreeImage_GetBPP (aTmpBitmap) != 24)
443 {
444 FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
445 if (aTmpBitmap != myLibImage)
446 {
447 FreeImage_Unload (aTmpBitmap);
448 }
449 if (aTmpBitmap24 == NULL)
450 {
451 return false;
452 }
453 aTmpBitmap = aTmpBitmap24;
454 }
455
dc858f4c 456 // need conversion to image with palette (requires 24bit bitmap)
692613e5 457 anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
458 if (aTmpBitmap != myLibImage)
459 {
460 FreeImage_Unload (aTmpBitmap);
461 }
462 break;
463 }
464 case FIF_EXR:
465 {
dc858f4c 466 if (Format() == Image_Format_Gray
467 || Format() == Image_Format_Alpha)
692613e5 468 {
469 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
470 }
dc858f4c 471 else if (Format() == Image_Format_RGBA
472 || Format() == Image_Format_BGRA)
692613e5 473 {
474 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
475 }
476 else
477 {
478 FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
479 if (aImgTypeFI != FIT_RGBF
480 && aImgTypeFI != FIT_RGBAF
481 && aImgTypeFI != FIT_FLOAT)
482 {
483 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
484 }
485 }
486 break;
487 }
488 default:
489 {
490 if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
491 {
492 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
493 if (anImageToDump == NULL)
494 {
495 return false;
496 }
497 }
498
499 if (FreeImage_GetBPP (anImageToDump) != 24)
500 {
501 FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
502 if (anImageToDump != myLibImage)
503 {
504 FreeImage_Unload (anImageToDump);
505 }
506 if (aTmpBitmap24 == NULL)
507 {
508 return false;
509 }
510 anImageToDump = aTmpBitmap24;
511 }
512 break;
513 }
514 }
515
516 if (anImageToDump == NULL)
517 {
518 return false;
519 }
520
7aa1b65c 521#ifdef _WIN32
fb0b0531 522 bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString()) != FALSE);
7aa1b65c 523#else
524 bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE);
525#endif
692613e5 526 if (anImageToDump != myLibImage)
527 {
528 FreeImage_Unload (anImageToDump);
529 }
530 return isSaved;
531#else
532 const Standard_Integer aLen = theFileName.Length();
533 if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
29cb310a 534 && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 )
692613e5 535 {
536 return savePPM (theFileName);
537 }
0797d9d3 538#ifdef OCCT_DEBUG
692613e5 539 std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n";
63c629aa 540#endif
692613e5 541 return savePPM (theFileName);
542#endif
543}
544
545// =======================================================================
546// function : AdjustGamma
547// purpose :
548// =======================================================================
7aa1b65c 549bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr)
692613e5 550{
7aa1b65c 551#ifdef HAVE_FREEIMAGE
692613e5 552 return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE;
553#else
7aa1b65c 554 (void )theGammaCorr;
555 return false;
35e08fe8 556#endif
7aa1b65c 557}