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 | //======================================================================= |
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 | |
85e096c3 |
419 | // ======================================================================= |
420 | // function : PixelColor |
421 | // purpose : |
422 | // ======================================================================= |
7fd59977 |
423 | Quantity_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 | // ======================================================================= |
434 | Quantity_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 | } |