0022752: Fix compilation on Unix with FreeImage and GL2PS support
[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,
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//=======================================================================
205Image_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//=======================================================================
265Image_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//=======================================================================
301void Image_PixMap::Destroy()
302{
303 myImage = Image_HPrivateImage();
304}
305
306//=======================================================================
307//function : Dump
308//purpose :
309//=======================================================================
310Standard_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
373Aspect_Handle Image_PixMap::PixmapID() const
374{
375 return Aspect_Handle();
376}
377
378void 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
417Quantity_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}