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