0023156: Image_PixMap::PixelColor() extended to return alpha value
[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,
124                                   Quantity_Parameter&    theAlpha) const
125     {
126       RGBQuad_t* aPixel = (RGBQuad_t* )&getScanLine (theRow)[theCol * myBytesPerPixel];
127       theAlpha = (myBytesPerPixel > 3) ? (Standard_Real (aPixel->rgbReserved) / 255.0) : 1.0;
128       return Quantity_Color (Standard_Real (aPixel->rgbRed)   / 255.0,
129                              Standard_Real (aPixel->rgbGreen) / 255.0,
130                              Standard_Real (aPixel->rgbBlue)  / 255.0,
131                              Quantity_TOC_RGB);
132     }
133
134     Standard_Boolean savePPM (const Standard_CString theFileName) const
135     {
136       // Open file
137       FILE* pFile = fopen (theFileName, "wb");
138       if (pFile == NULL)
139       {
140         return Standard_False;
141       }
142
143       // Write header
144       fprintf (pFile, "P6\n%d %d\n255\n", mySizeX, mySizeY);
145
146       // Write pixel data
147       Standard_Byte* aScanLine;
148       RGBQuad_t* aPixel;
149       // image stored upside-down
150       for (Standard_Integer aRow = mySizeY - 1; aRow >= 0; --aRow)
151       {
152         aScanLine = getScanLine (aRow);
153         for (Standard_Integer aCol = 0; aCol < mySizeX; ++aCol)
154         {
155           aPixel = (RGBQuad_t* )&aScanLine[aCol * myBytesPerPixel];
156           fwrite (&aPixel->rgbRed,   1, 1, pFile);
157           fwrite (&aPixel->rgbGreen, 1, 1, pFile);
158           fwrite (&aPixel->rgbBlue,  1, 1, pFile);
159         }
160       }
161
162       // Close file
163       fclose (pFile);
164       return Standard_True;
165     }
166
167     Standard_Integer getMaxRowAligmentBytes() const
168     {
169       Standard_Integer aDeltaBytes = myBytesPerLine - myBytesPerPixel * mySizeX;
170       for (Standard_Integer anAligment = 16; anAligment > 1; anAligment /= 2)
171       {
172         if (isRowAlignedTo (anAligment, aDeltaBytes))
173         {
174           return anAligment;
175         }
176       }
177       return 1;
178     }
179
180   private:
181
182     Standard_Boolean isRowAlignedTo (const Standard_Integer theAligmentBytes,
183                                      const Standard_Integer theDeltaBytes) const
184     {
185       return (theDeltaBytes < theAligmentBytes) &&
186              ((myBytesPerLine % theAligmentBytes) == 0);
187     }
188
189   private:
190
191     Standard_Byte* myDataPtr;
192     Standard_Integer mySizeX;
193     Standard_Integer mySizeY;
194     Standard_Integer myBytesPerLine;
195     Standard_Integer myBytesPerPixel;
196
197   };
198 #endif
199
200 #include <gp.hxx>
201 #include <TCollection_AsciiString.hxx>
202
203 //=======================================================================
204 //function : Image_PixMap
205 //purpose  :
206 //=======================================================================
207 Image_PixMap::Image_PixMap (const Standard_Integer theWidth,
208                             const Standard_Integer theHeight,
209                             const Image_TypeOfImage theType)
210 :       Aspect_PixMap (theWidth, theHeight, 1),
211         myImage()
212 {
213 #ifdef HAVE_FREEIMAGE
214   FREE_IMAGE_TYPE aFIType = FIT_UNKNOWN;
215   int aBitsPerPixel = 0;
216   switch (theType)
217   {
218     case Image_TOI_RGBA:
219       aFIType = FIT_BITMAP;
220       aBitsPerPixel = 32;
221       break;
222     case Image_TOI_RGBF:
223       aFIType = FIT_RGBF;
224       aBitsPerPixel = 96;
225       break;
226     case Image_TOI_RGBAF:
227       aFIType = FIT_RGBAF;
228       aBitsPerPixel = 128;
229       break;
230     case Image_TOI_FLOAT:
231       aFIType = FIT_FLOAT;
232       aBitsPerPixel = 32;
233       break;
234     case Image_TOI_RGB:
235     default:
236       aFIType = FIT_BITMAP;
237       aBitsPerPixel = 24;
238       break;
239   }
240   myImage = new fipImage (aFIType, theWidth, theHeight, aBitsPerPixel);
241 #else
242   Standard_Integer aBytesPerPixel = 0;
243   switch (theType)
244   {
245     case Image_TOI_RGBAF:
246       std::cerr << "Float formats not supported\n";
247     case Image_TOI_RGBA:
248       aBytesPerPixel = 4;
249       break;
250     case Image_TOI_RGBF:
251     case Image_TOI_FLOAT:
252       std::cerr << "Float formats not supported\n";
253     case Image_TOI_RGB:
254     default:
255       aBytesPerPixel = 3;
256       break;
257   }
258   myImage = new fipImage (theWidth, theHeight, 0, aBytesPerPixel);
259   //
260 #endif
261 }
262
263 //=======================================================================
264 //function : Image_PixMap
265 //purpose  :
266 //=======================================================================
267 Image_PixMap::Image_PixMap (const Standard_PByte theDataPtr,
268                             const Standard_Integer theWidth, const Standard_Integer theHeight,
269                             const Standard_Integer thePitch, const Standard_Integer theBitsPerPixel,
270                             const Standard_Boolean theIsTopDown)
271 :       Aspect_PixMap (theWidth, theHeight, 1),
272         myImage (new fipImage())
273 {
274 #ifdef HAVE_FREEIMAGE
275   *myImage = FreeImage_ConvertFromRawBits (theDataPtr,
276                                            theWidth, theHeight,
277                                            thePitch, theBitsPerPixel,
278                                            0, 0, 0,
279                                            theIsTopDown);
280   if (theBitsPerPixel != 24)
281   {
282     myImage->convertTo24Bits();
283   }
284 #else
285   myImage = new fipImage (theWidth, theHeight, thePitch, theBitsPerPixel / 8);
286   Standard_Integer aRowStart = !theIsTopDown ? 0 : (theHeight - 1);
287   Standard_Integer aRowDelta = !theIsTopDown ? 1 : -1;
288   for (Standard_Integer aRowFrom (aRowStart), aRowTo (0);
289        aRowFrom >= 0 && aRowFrom < theHeight;
290        aRowFrom += aRowDelta, ++aRowTo)
291   {
292     memcpy (myImage->getScanLine (aRowTo),
293             &theDataPtr[aRowFrom * thePitch],
294             myImage->getBytesPerLine());
295   }
296 #endif
297 }
298
299 //=======================================================================
300 //function : Destroy
301 //purpose  :
302 //=======================================================================
303 void Image_PixMap::Destroy()
304 {
305   myImage = Image_HPrivateImage();
306 }
307
308 //=======================================================================
309 //function : Dump
310 //purpose  :
311 //=======================================================================
312 Standard_Boolean Image_PixMap::Dump (const Standard_CString theFilename,
313                                      const Standard_Real theGammaCorr) const
314 {
315 #ifdef HAVE_FREEIMAGE
316   FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFilename);
317   if (anImageFormat == FIF_UNKNOWN)
318   {
319     std::cerr << "Image_PixMap, image format doesn't supported!\n";
320     return Standard_False;
321   }
322
323   Standard_Boolean isCopied = Standard_False;
324   Image_HPrivateImage anImageToDump = myImage;
325   if (Abs (theGammaCorr - 1.0) > gp::Resolution())
326   {
327     if (!isCopied)
328     {
329       isCopied = Standard_True;
330       anImageToDump = new fipImage (*myImage);
331     }
332     anImageToDump->adjustGamma (theGammaCorr);
333   }
334
335   switch (anImageFormat)
336   {
337     case FIF_GIF:
338       if (!isCopied)
339       {
340         isCopied = Standard_True;
341         anImageToDump = new fipImage (*myImage);
342       }
343       // need convertion to image with pallete
344       anImageToDump->colorQuantize (FIQ_NNQUANT);
345       break;
346     case FIF_EXR:
347       if (myImage->getImageType() == FIT_BITMAP)
348       {
349         if (!isCopied)
350         {
351           isCopied = Standard_True;
352           anImageToDump = new fipImage (*myImage);
353         }
354         anImageToDump->convertToType (FIT_RGBF);
355       }
356       break;
357     default:
358       if (myImage->getImageType() != FIT_BITMAP)
359       {
360         if (!isCopied)
361         {
362           isCopied = Standard_True;
363           anImageToDump = new fipImage (*myImage);
364         }
365         anImageToDump->convertToType (FIT_BITMAP);
366       }
367       break;
368   }
369   return anImageToDump->save (theFilename);
370 #else
371   return myImage->savePPM (theFilename);
372 #endif
373 }
374
375 Aspect_Handle Image_PixMap::PixmapID() const
376 {
377   return Aspect_Handle();
378 }
379
380 void Image_PixMap::AccessBuffer (Image_CRawBufferData& theBuffer) const
381 {
382   theBuffer.widthPx  = myImage->getWidth();
383   theBuffer.heightPx = myImage->getHeight();
384 #ifdef HAVE_FREEIMAGE
385   theBuffer.rowAligmentBytes = 4; // 32 bits according to FreeImage documentation
386   switch (myImage->getImageType())
387   {
388     case FIT_FLOAT:
389       theBuffer.format = TDepthComponent;
390       theBuffer.type = TFloat;
391       break;
392     case FIT_RGBF:
393       theBuffer.format = TRGB;
394       theBuffer.type = TFloat;
395       break;
396     case FIT_RGBAF:
397       theBuffer.format = TRGBA;
398       theBuffer.type = TFloat;
399       break;
400     case FIT_BITMAP:
401     default:
402     #if defined(FREEIMAGE_BIGENDIAN)
403       theBuffer.format = (myImage->getColorType() == FIC_RGBALPHA) ? TRGBA : TRGB;
404     #else
405       theBuffer.format = (myImage->getColorType() == FIC_RGBALPHA) ? TBGRA : TBGR;
406     #endif
407       theBuffer.type = TUByte;
408       break;
409   }
410   theBuffer.dataPtr = myImage->accessPixels();
411 #else
412   theBuffer.rowAligmentBytes = myImage->getMaxRowAligmentBytes();
413   theBuffer.format = (myImage->getBytesPerPixel() == 4) ? TBGRA : TBGR;
414   theBuffer.type = TUByte;
415   theBuffer.dataPtr = myImage->getData();
416 #endif
417 }
418
419 // =======================================================================
420 // function : PixelColor
421 // purpose  :
422 // =======================================================================
423 Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
424                                          const Standard_Integer theY) const
425 {
426   Quantity_Parameter aDummy;
427   return PixelColor (theX, theY, aDummy);
428 }
429
430 // =======================================================================
431 // function : PixelColor
432 // purpose  :
433 // =======================================================================
434 Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
435                                          const Standard_Integer theY,
436                                          Quantity_Parameter&    theAlpha) const
437 {
438   Standard_Integer aScanlineId = myImage->getHeight() - theY - 1;
439   if (theX < 0 || (unsigned int )theX >= (unsigned int )myImage->getWidth() ||
440       theY < 0 || (unsigned int )theY >= (unsigned int )myImage->getHeight())
441   {
442     theAlpha = 0.0; // transparent
443     return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
444   }
445 #ifdef HAVE_FREEIMAGE
446   else if (myImage->getImageType() == FIT_BITMAP)
447   {
448     RGBQUAD aValue; memset (&aValue, 0, sizeof(aValue));
449     myImage->getPixelColor (theX, aScanlineId, &aValue);
450     theAlpha = (myImage->getColorType() == FIC_RGBALPHA) ? (Standard_Real (aValue.rgbReserved) / 255.0) : 1.0;
451     return Quantity_Color (Standard_Real (aValue.rgbRed)   / 255.0,
452                            Standard_Real (aValue.rgbGreen) / 255.0,
453                            Standard_Real (aValue.rgbBlue)  / 255.0,
454                            Quantity_TOC_RGB);
455   }
456   else
457   {
458     switch (myImage->getImageType())
459     {
460       case FIT_FLOAT:
461       {
462         float* aScanLine = (float* )myImage->getScanLine (aScanlineId);
463         Quantity_Parameter aValue = Quantity_Parameter (aScanLine[theX]);
464         theAlpha = 1.0; // opaque
465         return Quantity_Color (aValue, aValue, aValue, Quantity_TOC_RGB);
466       }
467       case FIT_RGBF:
468       {
469         FIRGBF* aScanLine = (FIRGBF* )myImage->getScanLine (aScanlineId);
470         FIRGBF* aPixel = &aScanLine[theX];
471         theAlpha = 1.0; // opaque
472         return Quantity_Color (Quantity_Parameter (aPixel->red),
473                                Quantity_Parameter (aPixel->green),
474                                Quantity_Parameter (aPixel->blue),
475                                Quantity_TOC_RGB);
476       }
477       case FIT_RGBAF:
478       {
479         FIRGBAF* aScanLine = (FIRGBAF* )myImage->getScanLine (aScanlineId);
480         FIRGBAF* aPixel = &aScanLine[theX];
481         theAlpha = aPixel->alpha;
482         return Quantity_Color (Quantity_Parameter (aPixel->red),
483                                Quantity_Parameter (aPixel->green),
484                                Quantity_Parameter (aPixel->blue),
485                                Quantity_TOC_RGB);
486       }
487       default:
488       {
489         // not supported image type
490         theAlpha = 0.0; // transparent
491         return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
492       }
493     }
494   }
495 #else
496   return myImage->getPixelColor (theX, aScanlineId, theAlpha);
497 #endif
498 }