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