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