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>
37 static Image_PixMap::ImgFormat convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI,
38 FREE_IMAGE_COLOR_TYPE theColorTypeFI,
39 unsigned theBitsPerPixel)
43 case FIT_RGBF: return Image_PixMap::ImgRGBF;
44 case FIT_RGBAF: return Image_PixMap::ImgRGBAF;
45 case FIT_FLOAT: return Image_PixMap::ImgGrayF;
48 switch (theColorTypeFI)
52 return Image_PixMap::ImgGray;
56 if (Image_PixMap::IsBigEndianHost())
58 return (theBitsPerPixel == 32) ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgRGB;
62 return (theBitsPerPixel == 32) ? Image_PixMap::ImgBGR32 : Image_PixMap::ImgBGR;
67 return Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA;
70 return Image_PixMap::ImgUNKNOWN;
74 return Image_PixMap::ImgUNKNOWN;
78 static FREE_IMAGE_TYPE convertToFreeFormat (Image_PixMap::ImgFormat theFormat)
82 case Image_PixMap::ImgGrayF:
83 case Image_PixMap::ImgAlphaF:
85 case Image_PixMap::ImgRGBAF:
87 case Image_PixMap::ImgRGBF:
89 case Image_PixMap::ImgRGBA:
90 case Image_PixMap::ImgBGRA:
91 case Image_PixMap::ImgRGB32:
92 case Image_PixMap::ImgBGR32:
93 case Image_PixMap::ImgRGB:
94 case Image_PixMap::ImgBGR:
95 case Image_PixMap::ImgGray:
96 case Image_PixMap::ImgAlpha:
106 // =======================================================================
107 // function : Image_AlienPixMap
109 // =======================================================================
110 Image_AlienPixMap::Image_AlienPixMap()
116 // =======================================================================
117 // function : ~Image_AlienPixMap
119 // =======================================================================
120 Image_AlienPixMap::~Image_AlienPixMap()
125 // =======================================================================
126 // function : InitWrapper
128 // =======================================================================
129 bool Image_AlienPixMap::InitWrapper (ImgFormat,
139 // =======================================================================
140 // function : InitTrash
142 // =======================================================================
143 #ifdef HAVE_FREEIMAGE
144 bool Image_AlienPixMap::InitTrash (ImgFormat thePixelFormat,
145 const Standard_Size theSizeX,
146 const Standard_Size theSizeY,
147 const Standard_Size /*theSizeRowBytes*/)
150 FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat);
151 int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8;
152 if (aFormatFI == FIT_UNKNOWN)
154 aFormatFI = FIT_BITMAP;
158 FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel);
159 Image_PixMap::ImgFormat aFormat = convertFromFreeFormat (FreeImage_GetImageType (anImage),
160 FreeImage_GetColorType (anImage),
161 FreeImage_GetBPP (anImage));
162 if (thePixelFormat == Image_PixMap::ImgBGR32
163 || thePixelFormat == Image_PixMap::ImgRGB32)
165 //FreeImage_SetTransparent (anImage, FALSE);
166 aFormat = (aFormat == Image_PixMap::ImgBGRA) ? Image_PixMap::ImgBGR32 : Image_PixMap::ImgRGB32;
169 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
170 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
173 // assign image after wrapper initialization (virtual Clear() called inside)
174 myLibImage = anImage;
178 bool Image_AlienPixMap::InitTrash (ImgFormat thePixelFormat,
179 const Standard_Size theSizeX,
180 const Standard_Size theSizeY,
181 const Standard_Size theSizeRowBytes)
183 return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes);
187 // =======================================================================
188 // function : InitCopy
190 // =======================================================================
191 bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy)
193 if (&theCopy == this)
195 // self-copying disallowed
198 if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes()))
203 if (myImgFormat == theCopy.Format())
205 if (SizeRowBytes() == theCopy.SizeRowBytes()
206 && TopDownInc() == theCopy.TopDownInc())
208 // copy with one call
209 memcpy (ChangeData(), theCopy.Data(), std::min (SizeBytes(), theCopy.SizeBytes()));
214 const Standard_Size aRowSizeBytes = std::min (SizeRowBytes(), theCopy.SizeRowBytes());
215 for (Standard_Size aRow = 0; aRow < myData.SizeY; ++aRow)
217 memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes);
222 // pixel format conversion required
227 // =======================================================================
230 // =======================================================================
231 void Image_AlienPixMap::Clear()
233 Image_PixMap::Clear();
234 #ifdef HAVE_FREEIMAGE
235 if (myLibImage != NULL)
237 FreeImage_Unload (myLibImage);
243 // =======================================================================
246 // =======================================================================
247 #ifdef HAVE_FREEIMAGE
248 bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath)
253 const TCollection_ExtendedString aFileNameW (theImagePath.ToCString(), Standard_True);
254 FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileTypeU ((const wchar_t* )aFileNameW.ToExtString(), 0);
256 FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0);
258 if (aFIF == FIF_UNKNOWN)
260 // no signature? try to guess the file format from the file extension
261 aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString());
263 if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
265 TCollection_AsciiString aMessage = "Error: image file '";
266 aMessage.AssignCat (theImagePath);
267 aMessage.AssignCat ("' has unsupported file format.");
268 ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
275 // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
276 aLoadFlags = GIF_PLAYBACK;
278 else if (aFIF == FIF_ICO)
280 // convert to 32bpp and create an alpha channel from the AND-mask when loading
281 aLoadFlags = ICO_MAKEALPHA;
285 FIBITMAP* anImage = FreeImage_LoadU (aFIF, (const wchar_t* )aFileNameW.ToExtString(), aLoadFlags);
287 FIBITMAP* anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags);
291 TCollection_AsciiString aMessage = "Error: image file '";
292 aMessage.AssignCat (theImagePath);
293 aMessage.AssignCat ("' is missing or invalid.");
294 ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
298 Image_PixMap::ImgFormat aFormat = convertFromFreeFormat (FreeImage_GetImageType (anImage),
299 FreeImage_GetColorType (anImage),
300 FreeImage_GetBPP (anImage));
301 if (aFormat == Image_PixMap::ImgUNKNOWN)
303 //anImage = FreeImage_ConvertTo24Bits (anImage);
304 TCollection_AsciiString aMessage = "Error: image file '";
305 aMessage.AssignCat (theImagePath);
306 aMessage.AssignCat ("' has unsupported pixel format.");
307 ::Message::DefaultMessenger()->Send (aMessage, Message_Fail);
311 Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
312 FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
315 // assign image after wrapper initialization (virtual Clear() called inside)
316 myLibImage = anImage;
320 bool Image_AlienPixMap::Load (const TCollection_AsciiString&)
327 // =======================================================================
328 // function : savePPM
330 // =======================================================================
331 bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const
339 FILE* aFile = OSD_OpenFile (theFileName.ToCString(), "wb");
346 fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY());
347 fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n");
350 Quantity_Color aColor;
351 Quantity_Parameter aDummy;
353 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
355 for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
357 // extremely SLOW but universal (implemented for all supported pixel formats)
358 aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow, aDummy);
359 aByte = Standard_Byte(aColor.Red() * 255.0); fwrite (&aByte, 1, 1, aFile);
360 aByte = Standard_Byte(aColor.Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
361 aByte = Standard_Byte(aColor.Blue() * 255.0); fwrite (&aByte, 1, 1, aFile);
370 // =======================================================================
373 // =======================================================================
374 bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName)
376 #ifdef HAVE_FREEIMAGE
377 if (myLibImage == NULL)
383 const TCollection_ExtendedString aFileNameW (theFileName.ToCString(), Standard_True);
384 FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU ((const wchar_t* )aFileNameW.ToExtString());
386 FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString());
388 if (anImageFormat == FIF_UNKNOWN)
391 std::cerr << "Image_PixMap, image format doesn't supported!\n";
398 FreeImage_FlipVertical (myLibImage);
402 // FreeImage doesn't provide flexible format convertion API
403 // so we should perform multiple convertions in some cases!
404 FIBITMAP* anImageToDump = myLibImage;
405 switch (anImageFormat)
410 if (Format() == Image_PixMap::ImgBGR32
411 || Format() == Image_PixMap::ImgRGB32)
413 // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
414 for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
416 for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
418 myData.ChangeValue (aRow, aCol)[3] = 0xFF;
422 else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
424 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
430 FIBITMAP* aTmpBitmap = myLibImage;
431 if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
433 aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
434 if (aTmpBitmap == NULL)
440 if (FreeImage_GetBPP (aTmpBitmap) != 24)
442 FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
443 if (aTmpBitmap != myLibImage)
445 FreeImage_Unload (aTmpBitmap);
447 if (aTmpBitmap24 == NULL)
451 aTmpBitmap = aTmpBitmap24;
454 // need convertion to image with pallete (requires 24bit bitmap)
455 anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
456 if (aTmpBitmap != myLibImage)
458 FreeImage_Unload (aTmpBitmap);
464 if (Format() == Image_PixMap::ImgGray
465 || Format() == Image_PixMap::ImgAlpha)
467 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
469 else if (Format() == Image_PixMap::ImgRGBA
470 || Format() == Image_PixMap::ImgBGRA)
472 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
476 FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
477 if (aImgTypeFI != FIT_RGBF
478 && aImgTypeFI != FIT_RGBAF
479 && aImgTypeFI != FIT_FLOAT)
481 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
488 if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
490 anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
491 if (anImageToDump == NULL)
497 if (FreeImage_GetBPP (anImageToDump) != 24)
499 FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
500 if (anImageToDump != myLibImage)
502 FreeImage_Unload (anImageToDump);
504 if (aTmpBitmap24 == NULL)
508 anImageToDump = aTmpBitmap24;
514 if (anImageToDump == NULL)
520 bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, (const wchar_t* )aFileNameW.ToExtString()) != FALSE);
522 bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE);
524 if (anImageToDump != myLibImage)
526 FreeImage_Unload (anImageToDump);
530 const Standard_Integer aLen = theFileName.Length();
531 if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
532 && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 )
534 return savePPM (theFileName);
537 std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n";
539 return savePPM (theFileName);
543 // =======================================================================
544 // function : AdjustGamma
546 // =======================================================================
547 bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr)
549 #ifdef HAVE_FREEIMAGE
550 return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE;