0022752: Fix compilation on Unix with FreeImage and GL2PS support
[occt.git] / src / Image / Image_PixMap.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 <FreeImagePlus.h>
26   #include <Image_PixMap.ixx>
27   /* OCC22216 NOTE: linker dependency can be switched off by undefining macro */ 
28   #ifdef _MSC_VER
29   #pragma comment( lib, "FreeImage.lib" )
30   #pragma comment( lib, "FreeImagePlus.lib" )
31   #endif
32 #else
33   #include <Image_PixMap.ixx>
34   #include <fstream>
35
36   #if (defined(BYTE_ORDER)   && BYTE_ORDER==BIG_ENDIAN) || \
37       (defined(__BYTE_ORDER) && __BYTE_ORDER==__BIG_ENDIAN) || \
38        defined(__BIG_ENDIAN__)
39     #define THE_BIGENDIAN
40   #endif
41
42   // dummy class which can only dump to PPM format
43   class fipImage
44   {
45   public:
46
47     typedef struct tagRGBQuad {
48     #ifndef THE_BIGENDIAN
49       Standard_Byte rgbBlue;
50       Standard_Byte rgbGreen;
51       Standard_Byte rgbRed;
52     #else
53       Standard_Byte rgbRed;
54       Standard_Byte rgbGreen;
55       Standard_Byte rgbBlue;
56     #endif
57       Standard_Byte rgbReserved;
58     } RGBQuad_t;
59
60   public:
61
62     fipImage()
63     : myDataPtr(NULL),
64       mySizeX(0),
65       mySizeY(0),
66       myBytesPerLine(0),
67       myBytesPerPixel(3)
68     {
69       //
70     }
71
72     fipImage (const Standard_Integer theSizeX, const Standard_Integer theSizeY,
73               const Standard_Integer theBytesPerLine = 0, const Standard_Integer theBytesPerPixel = 3)
74     : myDataPtr(NULL),
75       mySizeX (theSizeX),
76       mySizeY (theSizeY),
77       myBytesPerLine (theBytesPerLine),
78       myBytesPerPixel (theBytesPerPixel)
79     {
80       if (myBytesPerLine == 0)
81       {
82         myBytesPerLine = mySizeX * myBytesPerPixel;
83       }
84       myDataPtr = new Standard_Byte[myBytesPerLine * mySizeY];
85     }
86
87     ~fipImage()
88     {
89       delete[] myDataPtr;
90     }
91
92     Standard_Integer getHeight() const
93     {
94       return mySizeY;
95     }
96
97     Standard_Integer getWidth() const
98     {
99       return mySizeX;
100     }
101
102     Standard_Integer getBytesPerPixel() const
103     {
104       return myBytesPerPixel;
105     }
106
107     Standard_Integer getBytesPerLine() const
108     {
109       return myBytesPerLine;
110     }
111
112     Standard_Byte* getData() const
113     {
114       return myDataPtr;
115     }
116
117     Standard_Byte* getScanLine (const Standard_Integer theRow) const
118     {
119       return &myDataPtr[theRow * myBytesPerLine];
120     }
121
122     Quantity_Color getPixelColor (const Standard_Integer theCol,
123                                   const Standard_Integer theRow) const
124     {
125       RGBQuad_t* aPixel = (RGBQuad_t* )&getScanLine (theRow)[theCol * myBytesPerPixel];
126       return Quantity_Color (Standard_Real (aPixel->rgbRed)   / 255.0,
127                              Standard_Real (aPixel->rgbGreen) / 255.0,
128                              Standard_Real (aPixel->rgbBlue)  / 255.0,
129                              Quantity_TOC_RGB);
130     }
131
132     Standard_Boolean savePPM (const Standard_CString theFileName) const
133     {
134       // Open file
135       FILE* pFile = fopen (theFileName, "wb");
136       if (pFile == NULL)
137       {
138         return Standard_False;
139       }
140
141       // Write header
142       fprintf (pFile, "P6\n%d %d\n255\n", mySizeX, mySizeY);
143
144       // Write pixel data
145       Standard_Byte* aScanLine;
146       RGBQuad_t* aPixel;
147       // image stored upside-down
148       for (Standard_Integer aRow = mySizeY - 1; aRow >= 0; --aRow)
149       {
150         aScanLine = getScanLine (aRow);
151         for (Standard_Integer aCol = 0; aCol < mySizeX; ++aCol)
152         {
153           aPixel = (RGBQuad_t* )&aScanLine[aCol * myBytesPerPixel];
154           fwrite (&aPixel->rgbRed,   1, 1, pFile);
155           fwrite (&aPixel->rgbGreen, 1, 1, pFile);
156           fwrite (&aPixel->rgbBlue,  1, 1, pFile);
157         }
158       }
159
160       // Close file
161       fclose (pFile);
162       return Standard_True;
163     }
164
165     Standard_Integer getMaxRowAligmentBytes() const
166     {
167       Standard_Integer aDeltaBytes = myBytesPerLine - myBytesPerPixel * mySizeX;
168       for (Standard_Integer anAligment = 16; anAligment > 1; anAligment /= 2)
169       {
170         if (isRowAlignedTo (anAligment, aDeltaBytes))
171         {
172           return anAligment;
173         }
174       }
175       return 1;
176     }
177
178   private:
179
180     Standard_Boolean isRowAlignedTo (const Standard_Integer theAligmentBytes,
181                                      const Standard_Integer theDeltaBytes) const
182     {
183       return (theDeltaBytes < theAligmentBytes) &&
184              ((myBytesPerLine % theAligmentBytes) == 0);
185     }
186
187   private:
188
189     Standard_Byte* myDataPtr;
190     Standard_Integer mySizeX;
191     Standard_Integer mySizeY;
192     Standard_Integer myBytesPerLine;
193     Standard_Integer myBytesPerPixel;
194
195   };
196 #endif
197
198 #include <gp.hxx>
199 #include <TCollection_AsciiString.hxx>
200
201 //=======================================================================
202 //function : Image_PixMap
203 //purpose  :
204 //=======================================================================
205 Image_PixMap::Image_PixMap (const Standard_Integer theWidth,
206                             const Standard_Integer theHeight,
207                             const Image_TypeOfImage theType)
208 :       Aspect_PixMap (theWidth, theHeight, 1),
209         myImage()
210 {
211 #ifdef HAVE_FREEIMAGE
212   FREE_IMAGE_TYPE aFIType = FIT_UNKNOWN;
213   int aBitsPerPixel = 0;
214   switch (theType)
215   {
216     case Image_TOI_RGBA:
217       aFIType = FIT_BITMAP;
218       aBitsPerPixel = 32;
219       break;
220     case Image_TOI_RGBF:
221       aFIType = FIT_RGBF;
222       aBitsPerPixel = 96;
223       break;
224     case Image_TOI_RGBAF:
225       aFIType = FIT_RGBAF;
226       aBitsPerPixel = 128;
227       break;
228     case Image_TOI_FLOAT:
229       aFIType = FIT_FLOAT;
230       aBitsPerPixel = 32;
231       break;
232     case Image_TOI_RGB:
233     default:
234       aFIType = FIT_BITMAP;
235       aBitsPerPixel = 24;
236       break;
237   }
238   myImage = new fipImage (aFIType, theWidth, theHeight, aBitsPerPixel);
239 #else
240   Standard_Integer aBytesPerPixel = 0;
241   switch (theType)
242   {
243     case Image_TOI_RGBAF:
244       std::cerr << "Float formats not supported\n";
245     case Image_TOI_RGBA:
246       aBytesPerPixel = 4;
247       break;
248     case Image_TOI_RGBF:
249     case Image_TOI_FLOAT:
250       std::cerr << "Float formats not supported\n";
251     case Image_TOI_RGB:
252     default:
253       aBytesPerPixel = 3;
254       break;
255   }
256   myImage = new fipImage (theWidth, theHeight, 0, aBytesPerPixel);
257   //
258 #endif
259 }
260
261 //=======================================================================
262 //function : Image_PixMap
263 //purpose  :
264 //=======================================================================
265 Image_PixMap::Image_PixMap (const Standard_PByte theDataPtr,
266                             const Standard_Integer theWidth, const Standard_Integer theHeight,
267                             const Standard_Integer thePitch, const Standard_Integer theBitsPerPixel,
268                             const Standard_Boolean theIsTopDown)
269 :       Aspect_PixMap (theWidth, theHeight, 1),
270         myImage (new fipImage())
271 {
272 #ifdef HAVE_FREEIMAGE
273   *myImage = FreeImage_ConvertFromRawBits (theDataPtr,
274                                            theWidth, theHeight,
275                                            thePitch, theBitsPerPixel,
276                                            0, 0, 0,
277                                            theIsTopDown);
278   if (theBitsPerPixel != 24)
279   {
280     myImage->convertTo24Bits();
281   }
282 #else
283   myImage = new fipImage (theWidth, theHeight, thePitch, theBitsPerPixel / 8);
284   Standard_Integer aRowStart = !theIsTopDown ? 0 : (theHeight - 1);
285   Standard_Integer aRowDelta = !theIsTopDown ? 1 : -1;
286   for (Standard_Integer aRowFrom (aRowStart), aRowTo (0);
287        aRowFrom >= 0 && aRowFrom < theHeight;
288        aRowFrom += aRowDelta, ++aRowTo)
289   {
290     memcpy (myImage->getScanLine (aRowTo),
291             &theDataPtr[aRowFrom * thePitch],
292             myImage->getBytesPerLine());
293   }
294 #endif
295 }
296
297 //=======================================================================
298 //function : Destroy
299 //purpose  :
300 //=======================================================================
301 void Image_PixMap::Destroy()
302 {
303   myImage = Image_HPrivateImage();
304 }
305
306 //=======================================================================
307 //function : Dump
308 //purpose  :
309 //=======================================================================
310 Standard_Boolean Image_PixMap::Dump (const Standard_CString theFilename,
311                                      const Standard_Real theGammaCorr) const
312 {
313 #ifdef HAVE_FREEIMAGE
314   FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFilename);
315   if (anImageFormat == FIF_UNKNOWN)
316   {
317     std::cerr << "Image_PixMap, image format doesn't supported!\n";
318     return Standard_False;
319   }
320
321   Standard_Boolean isCopied = Standard_False;
322   Image_HPrivateImage anImageToDump = myImage;
323   if (Abs (theGammaCorr - 1.0) > gp::Resolution())
324   {
325     if (!isCopied)
326     {
327       isCopied = Standard_True;
328       anImageToDump = new fipImage (*myImage);
329     }
330     anImageToDump->adjustGamma (theGammaCorr);
331   }
332
333   switch (anImageFormat)
334   {
335     case FIF_GIF:
336       if (!isCopied)
337       {
338         isCopied = Standard_True;
339         anImageToDump = new fipImage (*myImage);
340       }
341       // need convertion to image with pallete
342       anImageToDump->colorQuantize (FIQ_NNQUANT);
343       break;
344     case FIF_EXR:
345       if (myImage->getImageType() == FIT_BITMAP)
346       {
347         if (!isCopied)
348         {
349           isCopied = Standard_True;
350           anImageToDump = new fipImage (*myImage);
351         }
352         anImageToDump->convertToType (FIT_RGBF);
353       }
354       break;
355     default:
356       if (myImage->getImageType() != FIT_BITMAP)
357       {
358         if (!isCopied)
359         {
360           isCopied = Standard_True;
361           anImageToDump = new fipImage (*myImage);
362         }
363         anImageToDump->convertToType (FIT_BITMAP);
364       }
365       break;
366   }
367   return anImageToDump->save (theFilename);
368 #else
369   return myImage->savePPM (theFilename);
370 #endif
371 }
372
373 Aspect_Handle Image_PixMap::PixmapID() const
374 {
375   return Aspect_Handle();
376 }
377
378 void Image_PixMap::AccessBuffer (Image_CRawBufferData& theBuffer) const
379 {
380   theBuffer.widthPx  = myImage->getWidth();
381   theBuffer.heightPx = myImage->getHeight();
382 #ifdef HAVE_FREEIMAGE
383   theBuffer.rowAligmentBytes = 4; // 32 bits according to FreeImage documentation
384   switch (myImage->getImageType())
385   {
386     case FIT_FLOAT:
387       theBuffer.format = TDepthComponent;
388       theBuffer.type = TFloat;
389       break;
390     case FIT_RGBF:
391       theBuffer.format = TRGB;
392       theBuffer.type = TFloat;
393       break;
394     case FIT_RGBAF:
395       theBuffer.format = TRGBA;
396       theBuffer.type = TFloat;
397       break;
398     case FIT_BITMAP:
399     default:
400     #if defined(FREEIMAGE_BIGENDIAN)
401       theBuffer.format = (myImage->getColorType() == FIC_RGBALPHA) ? TRGBA : TRGB;
402     #else
403       theBuffer.format = (myImage->getColorType() == FIC_RGBALPHA) ? TBGRA : TBGR;
404     #endif
405       theBuffer.type = TUByte;
406       break;
407   }
408   theBuffer.dataPtr = myImage->accessPixels();
409 #else
410   theBuffer.rowAligmentBytes = myImage->getMaxRowAligmentBytes();
411   theBuffer.format = (myImage->getBytesPerPixel() == 4) ? TBGRA : TBGR;
412   theBuffer.type = TUByte;
413   theBuffer.dataPtr = myImage->getData();
414 #endif
415 }
416
417 Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
418                                          const Standard_Integer theY) const
419 {
420   Standard_Integer aScanlineId = myImage->getHeight() - theY - 1;
421   if (theX < 0 || theX >= (unsigned int)myImage->getWidth() ||
422       theY < 0 || theY >= (unsigned int)myImage->getHeight())
423   {
424     return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
425   }
426 #ifdef HAVE_FREEIMAGE
427   else if (myImage->getImageType() == FIT_BITMAP)
428   {
429     RGBQUAD aValue; memset (&aValue, 0, sizeof(aValue));
430     myImage->getPixelColor (theX, aScanlineId, &aValue);
431     return Quantity_Color (Standard_Real (aValue.rgbRed)   / 255.0,
432                            Standard_Real (aValue.rgbGreen) / 255.0,
433                            Standard_Real (aValue.rgbBlue)  / 255.0,
434                            Quantity_TOC_RGB);
435   }
436   else
437   {
438     switch (myImage->getImageType())
439     {
440       case FIT_FLOAT:
441       {
442         float* aScanLine = (float* )myImage->getScanLine (aScanlineId);
443         Quantity_Parameter aValue = Quantity_Parameter (aScanLine[theX]);
444         return Quantity_Color (aValue, aValue, aValue, Quantity_TOC_RGB);
445       }
446       case FIT_RGBF:
447       {
448         FIRGBF* aScanLine = (FIRGBF* )myImage->getScanLine (aScanlineId);
449         FIRGBF* aPixel = &aScanLine[theX];
450         return Quantity_Color (Quantity_Parameter (aPixel->red),
451                                Quantity_Parameter (aPixel->green),
452                                Quantity_Parameter (aPixel->blue),
453                                Quantity_TOC_RGB);
454       }
455       case FIT_RGBAF:
456       {
457         FIRGBAF* aScanLine = (FIRGBAF* )myImage->getScanLine (aScanlineId);
458         FIRGBAF* aPixel = &aScanLine[theX];
459         return Quantity_Color (Quantity_Parameter (aPixel->red),
460                                Quantity_Parameter (aPixel->green),
461                                Quantity_Parameter (aPixel->blue),
462                                Quantity_TOC_RGB);
463       }
464       default:
465       {
466         // not supported image type
467         return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
468       }
469     }
470   }
471 #else
472   return myImage->getPixelColor (theX, aScanlineId);
473 #endif
474 }