1 // Created on: 2010-09-16
3 // Copyright (c) 2010-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
17 #include <FreeImage.h>
20 #pragma comment( lib, "FreeImage.lib" )
24 #include <Image_AlienPixMap.hxx>
26 #include <Message.hxx>
27 #include <Message_Messenger.hxx>
28 #include <TCollection_AsciiString.hxx>
29 #include <TCollection_ExtendedString.hxx>
30 #include <OSD_OpenFile.hxx>
34 IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap,Image_PixMap)
39 static Image_PixMap::ImgFormat convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI,
40 FREE_IMAGE_COLOR_TYPE theColorTypeFI,
41 unsigned theBitsPerPixel)
45 case FIT_RGBF: return Image_PixMap::ImgRGBF;
46 case FIT_RGBAF: return Image_PixMap::ImgRGBAF;
47 case FIT_FLOAT: return Image_PixMap::ImgGrayF;
50 switch (theColorTypeFI)
54 return Image_PixMap::ImgGray;
58 if (Image_PixMap::IsBigEndianHost())
60 return (theBitsPerPixel == 32) ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgRGB;
64 return (theBitsPerPixel == 32) ? Image_PixMap::ImgBGR32 : Image_PixMap::ImgBGR;
69 return Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA;
72 return Image_PixMap::ImgUNKNOWN;
76 return Image_PixMap::ImgUNKNOWN;
80 static FREE_IMAGE_TYPE convertToFreeFormat (Image_PixMap::ImgFormat theFormat)
84 case Image_PixMap::ImgGrayF:
85 case Image_PixMap::ImgAlphaF:
87 case Image_PixMap::ImgRGBAF:
89 case Image_PixMap::ImgRGBF:
91 case Image_PixMap::ImgRGBA:
92 case Image_PixMap::ImgBGRA:
93 case Image_PixMap::ImgRGB32:
94 case Image_PixMap::ImgBGR32:
95 case Image_PixMap::ImgRGB:
96 case Image_PixMap::ImgBGR:
97 case Image_PixMap::ImgGray:
98 case Image_PixMap::ImgAlpha:
108 // =======================================================================
109 // function : Image_AlienPixMap
111 // =======================================================================
112 Image_AlienPixMap::Image_AlienPixMap()
118 // =======================================================================
119 // function : ~Image_AlienPixMap
121 // =======================================================================
122 Image_AlienPixMap::~Image_AlienPixMap()
127 // =======================================================================
128 // function : InitWrapper
130 // =======================================================================
131 bool Image_AlienPixMap::InitWrapper (ImgFormat,
141 // =======================================================================
142 // function : InitTrash
144 // =======================================================================
145 #ifdef HAVE_FREEIMAGE
146 bool Image_AlienPixMap::InitTrash (ImgFormat thePixelFormat,
147 const Standard_Size theSizeX,
148 const Standard_Size theSizeY,
149 const Standard_Size /*theSizeRowBytes*/)
152 FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat);
153 int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8;
154 if (aFormatFI == FIT_UNKNOWN)
156 aFormatFI = FIT_BITMAP;
160 FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel);
161 Image_PixMap::ImgFormat aFormat = convertFromFreeFormat (FreeImage_GetImageType (anImage),
162 FreeImage_GetColorType (anImage),
163 FreeImage_GetBPP (anImage));
164 if (thePixelFormat == Image_PixMap::ImgBGR32
165 || thePixelFormat == Image_PixMap::ImgRGB32)
167 //FreeImage_SetTransparent (anImage, FALSE);
168 aFormat = (aFormat == Image_PixMap::ImgBGRA) ? Image_PixMap::ImgBGR32 : Image_PixMap::ImgRGB32;
171 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
172 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
175 // assign image after wrapper initialization (virtual Clear() called inside)
176 myLibImage = anImage;
180 bool Image_AlienPixMap::InitTrash (ImgFormat thePixelFormat,
181 const Standard_Size theSizeX,
182 const Standard_Size theSizeY,
183 const Standard_Size theSizeRowBytes)
185 return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes);
189 // =======================================================================
190 // function : InitCopy
192 // =======================================================================
193 bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy)
195 if (&theCopy == this)
197 // self-copying disallowed
200 if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes()))
205 if (myImgFormat == theCopy.Format())
207 if (SizeRowBytes() == theCopy.SizeRowBytes()
208 && TopDownInc() == theCopy.TopDownInc())
210 // copy with one call
211 memcpy (ChangeData(), theCopy.Data(), std::min (SizeBytes(), theCopy.SizeBytes()));
216 const Standard_Size aRowSizeBytes = std::min (SizeRowBytes(), theCopy.SizeRowBytes());
217 for (Standard_Size aRow = 0; aRow < myData.SizeY; ++aRow)
219 memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes);
224 // pixel format conversion required
229 // =======================================================================
232 // =======================================================================
233 void Image_AlienPixMap::Clear()
235 Image_PixMap::Clear();
236 #ifdef HAVE_FREEIMAGE
237 if (myLibImage != NULL)
239 FreeImage_Unload (myLibImage);
245 // =======================================================================
248 // =======================================================================
249 #ifdef HAVE_FREEIMAGE
250 bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath)
255 const TCollection_ExtendedString aFileNameW (theImagePath.ToCString(), Standard_True);
256 FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeU ((const wchar_t* )aFileNameW.ToExtString(), 0);
258 FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0);
260 if (aFIF == FIF_UNKNOWN)
262 // no signature? try to guess the file format from the file extension
263 aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString());
265 if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
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);
277 // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
278 aLoadFlags = GIF_PLAYBACK;
280 else if (aFIF == FIF_ICO)
282 // convert to 32bpp and create an alpha channel from the AND-mask when loading
283 aLoadFlags = ICO_MAKEALPHA;
287 FIBITMAP* anImage = FreeImage_LoadU (aFIF, (const wchar_t* )aFileNameW.ToExtString(), aLoadFlags);
289 FIBITMAP* anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags);
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);
300 Image_PixMap::ImgFormat aFormat = convertFromFreeFormat (FreeImage_GetImageType (anImage),
301 FreeImage_GetColorType (anImage),
302 FreeImage_GetBPP (anImage));
303 if (aFormat == Image_PixMap::ImgUNKNOWN)
305 //anImage = FreeImage_ConvertTo24Bits (anImage);
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);
313 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
314 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
317 // assign image after wrapper initialization (virtual Clear() called inside)
318 myLibImage = anImage;
322 bool Image_AlienPixMap::Load (const TCollection_AsciiString&)
329 // =======================================================================
330 // function : savePPM
332 // =======================================================================
333 bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const
341 FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb");
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");
352 Quantity_Color aColor;
353 Quantity_Parameter aDummy;
355 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
357 for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
359 // extremely SLOW but universal (implemented for all supported pixel formats)
360 aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow, aDummy);
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);
372 // =======================================================================
375 // =======================================================================
376 bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName)
378 #ifdef HAVE_FREEIMAGE
379 if (myLibImage == NULL)
385 const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True);
386 FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU ((const wchar_t* )aFileNameW.ToExtString());
388 FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString());
390 if (anImageFormat == FIF_UNKNOWN)
393 std::cerr << "Image_PixMap, image format doesn't supported!\n";
400 FreeImage_FlipVertical (myLibImage);
404 // FreeImage doesn't provide flexible format convertion API
405 // so we should perform multiple convertions in some cases!
406 FIBITMAP* anImageToDump = myLibImage;
407 switch (anImageFormat)
412 if (Format() == Image_PixMap::ImgBGR32
413 || Format() == Image_PixMap::ImgRGB32)
415 // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
416 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
418 for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
420 myData.ChangeValue (aRow, aCol)[3] = 0xFF;
424 else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
426 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
432 FIBITMAP* aTmpBitmap = myLibImage;
433 if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
435 aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
436 if (aTmpBitmap == NULL)
442 if (FreeImage_GetBPP (aTmpBitmap) != 24)
444 FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
445 if (aTmpBitmap != myLibImage)
447 FreeImage_Unload (aTmpBitmap);
449 if (aTmpBitmap24 == NULL)
453 aTmpBitmap = aTmpBitmap24;
456 // need convertion to image with pallete (requires 24bit bitmap)
457 anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
458 if (aTmpBitmap != myLibImage)
460 FreeImage_Unload (aTmpBitmap);
466 if (Format() == Image_PixMap::ImgGray
467 || Format() == Image_PixMap::ImgAlpha)
469 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
471 else if (Format() == Image_PixMap::ImgRGBA
472 || Format() == Image_PixMap::ImgBGRA)
474 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
478 FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
479 if (aImgTypeFI != FIT_RGBF
480 && aImgTypeFI != FIT_RGBAF
481 && aImgTypeFI != FIT_FLOAT)
483 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
490 if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
492 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
493 if (anImageToDump == NULL)
499 if (FreeImage_GetBPP (anImageToDump) != 24)
501 FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
502 if (anImageToDump != myLibImage)
504 FreeImage_Unload (anImageToDump);
506 if (aTmpBitmap24 == NULL)
510 anImageToDump = aTmpBitmap24;
516 if (anImageToDump == NULL)
522 bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, (const wchar_t* )aFileNameW.ToExtString()) != FALSE);
524 bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE);
526 if (anImageToDump != myLibImage)
528 FreeImage_Unload (anImageToDump);
532 const Standard_Integer aLen = theFileName.Length();
533 if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
534 && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 )
536 return savePPM (theFileName);
539 std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n";
541 return savePPM (theFileName);
545 // =======================================================================
546 // function : AdjustGamma
548 // =======================================================================
549 bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr)
551 #ifdef HAVE_FREEIMAGE
552 return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE;