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