0023156: Image_PixMap::PixelColor() extended to return alpha value
[occt.git] / src / Image / Image_PixMap.cxx
CommitLineData
b311480e 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
498ce577 20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
7fd59977 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,
85e096c3 123 const Standard_Integer theRow,
124 Quantity_Parameter& theAlpha) const
7fd59977 125 {
126 RGBQuad_t* aPixel = (RGBQuad_t* )&getScanLine (theRow)[theCol * myBytesPerPixel];
85e096c3 127 theAlpha = (myBytesPerPixel > 3) ? (Standard_Real (aPixel->rgbReserved) / 255.0) : 1.0;
7fd59977 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//=======================================================================
207Image_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//=======================================================================
267Image_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//=======================================================================
303void Image_PixMap::Destroy()
304{
305 myImage = Image_HPrivateImage();
306}
307
308//=======================================================================
309//function : Dump
310//purpose :
311//=======================================================================
312Standard_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
375Aspect_Handle Image_PixMap::PixmapID() const
376{
377 return Aspect_Handle();
378}
379
380void 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
85e096c3 419// =======================================================================
420// function : PixelColor
421// purpose :
422// =======================================================================
7fd59977 423Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
424 const Standard_Integer theY) const
85e096c3 425{
426 Quantity_Parameter aDummy;
427 return PixelColor (theX, theY, aDummy);
428}
429
430// =======================================================================
431// function : PixelColor
432// purpose :
433// =======================================================================
434Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
435 const Standard_Integer theY,
436 Quantity_Parameter& theAlpha) const
7fd59977 437{
438 Standard_Integer aScanlineId = myImage->getHeight() - theY - 1;
85e096c3 439 if (theX < 0 || (unsigned int )theX >= (unsigned int )myImage->getWidth() ||
440 theY < 0 || (unsigned int )theY >= (unsigned int )myImage->getHeight())
7fd59977 441 {
85e096c3 442 theAlpha = 0.0; // transparent
7fd59977 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);
85e096c3 450 theAlpha = (myImage->getColorType() == FIC_RGBALPHA) ? (Standard_Real (aValue.rgbReserved) / 255.0) : 1.0;
7fd59977 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]);
85e096c3 464 theAlpha = 1.0; // opaque
7fd59977 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];
85e096c3 471 theAlpha = 1.0; // opaque
7fd59977 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];
85e096c3 481 theAlpha = aPixel->alpha;
7fd59977 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
85e096c3 490 theAlpha = 0.0; // transparent
7fd59977 491 return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
492 }
493 }
494 }
495#else
85e096c3 496 return myImage->getPixelColor (theX, aScanlineId, theAlpha);
7fd59977 497#endif
498}