692613e5 |
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 <FreeImage.h> |
26 | |
27 | #ifdef _MSC_VER |
28 | #pragma comment( lib, "FreeImage.lib" ) |
29 | #endif |
30 | #endif |
31 | |
32 | #include <Image_AlienPixMap.hxx> |
33 | #include <gp.hxx> |
34 | #include <TCollection_AsciiString.hxx> |
35 | #include <fstream> |
36 | |
37 | #ifdef HAVE_FREEIMAGE |
38 | namespace |
39 | { |
40 | static Image_PixMap::ImgFormat convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI, |
41 | FREE_IMAGE_COLOR_TYPE theColorTypeFI, |
42 | unsigned theBitsPerPixel) |
43 | { |
44 | switch (theFormatFI) |
45 | { |
46 | case FIT_RGBF: return Image_PixMap::ImgRGBF; |
47 | case FIT_RGBAF: return Image_PixMap::ImgRGBAF; |
48 | case FIT_FLOAT: return Image_PixMap::ImgGrayF; |
49 | case FIT_BITMAP: |
50 | { |
51 | switch (theColorTypeFI) |
52 | { |
53 | case FIC_MINISBLACK: |
54 | { |
55 | return Image_PixMap::ImgGray; |
56 | } |
57 | case FIC_RGB: |
58 | { |
59 | if (Image_PixMap::IsBigEndianHost()) |
60 | { |
61 | return (theBitsPerPixel == 32) ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgRGB; |
62 | } |
63 | else |
64 | { |
65 | return (theBitsPerPixel == 32) ? Image_PixMap::ImgBGR32 : Image_PixMap::ImgBGR; |
66 | } |
67 | } |
68 | case FIC_RGBALPHA: |
69 | { |
70 | return Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA; |
71 | } |
72 | default: |
73 | return Image_PixMap::ImgUNKNOWN; |
74 | } |
75 | } |
76 | default: |
77 | return Image_PixMap::ImgUNKNOWN; |
78 | } |
79 | } |
80 | |
81 | static FREE_IMAGE_TYPE convertToFreeFormat (Image_PixMap::ImgFormat theFormat) |
82 | { |
83 | switch (theFormat) |
84 | { |
85 | case Image_PixMap::ImgGrayF: |
86 | return FIT_FLOAT; |
87 | case Image_PixMap::ImgRGBAF: |
88 | return FIT_RGBAF; |
89 | case Image_PixMap::ImgRGBF: |
90 | return FIT_RGBF; |
91 | case Image_PixMap::ImgRGBA: |
92 | case Image_PixMap::ImgBGRA: |
93 | case Image_PixMap::ImgRGB32: |
94 | case Image_PixMap::ImgBGR32: |
95 | case Image_PixMap::ImgRGB: |
96 | case Image_PixMap::ImgBGR: |
97 | case Image_PixMap::ImgGray: |
98 | return FIT_BITMAP; |
99 | default: |
100 | return FIT_UNKNOWN; |
101 | } |
102 | } |
103 | }; |
104 | #endif |
105 | |
106 | IMPLEMENT_STANDARD_HANDLE (Image_AlienPixMap, Image_PixMap) |
107 | IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap, Image_PixMap) |
108 | |
109 | // ======================================================================= |
110 | // function : Image_AlienPixMap |
111 | // purpose : |
112 | // ======================================================================= |
113 | Image_AlienPixMap::Image_AlienPixMap() |
114 | : myLibImage (NULL) |
115 | { |
116 | SetTopDown (false); |
117 | } |
118 | |
119 | // ======================================================================= |
120 | // function : ~Image_AlienPixMap |
121 | // purpose : |
122 | // ======================================================================= |
123 | Image_AlienPixMap::~Image_AlienPixMap() |
124 | { |
125 | Clear(); |
126 | } |
127 | |
128 | // ======================================================================= |
129 | // function : InitWrapper |
130 | // purpose : |
131 | // ======================================================================= |
35e08fe8 |
132 | bool Image_AlienPixMap::InitWrapper (ImgFormat, |
133 | Standard_Byte*, |
134 | const Standard_Size, |
135 | const Standard_Size, |
136 | const Standard_Size) |
692613e5 |
137 | { |
138 | Clear(); |
139 | return false; |
140 | } |
141 | |
142 | // ======================================================================= |
143 | // function : InitTrash |
144 | // purpose : |
145 | // ======================================================================= |
498ce76b |
146 | #ifdef HAVE_FREEIMAGE |
692613e5 |
147 | bool Image_AlienPixMap::InitTrash (ImgFormat thePixelFormat, |
148 | const Standard_Size theSizeX, |
149 | const Standard_Size theSizeY, |
498ce76b |
150 | const Standard_Size /*theSizeRowBytes*/) |
692613e5 |
151 | { |
152 | Clear(); |
692613e5 |
153 | FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat); |
154 | int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8; |
155 | if (aFormatFI == FIT_UNKNOWN) |
156 | { |
157 | aFormatFI = FIT_BITMAP; |
158 | aBitsPerPixel = 24; |
159 | } |
160 | |
161 | FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel); |
162 | Image_PixMap::ImgFormat aFormat = convertFromFreeFormat (FreeImage_GetImageType (anImage), |
163 | FreeImage_GetColorType (anImage), |
164 | FreeImage_GetBPP (anImage)); |
165 | if (thePixelFormat == Image_PixMap::ImgBGR32 |
166 | || thePixelFormat == Image_PixMap::ImgRGB32) |
167 | { |
168 | //FreeImage_SetTransparent (anImage, FALSE); |
169 | aFormat = (aFormat == Image_PixMap::ImgBGRA) ? Image_PixMap::ImgBGR32 : Image_PixMap::ImgRGB32; |
170 | } |
171 | |
172 | Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage), |
173 | FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); |
174 | SetTopDown (false); |
175 | |
176 | // assign image after wrapper initialization (virtual Clear() called inside) |
177 | myLibImage = anImage; |
178 | return true; |
498ce76b |
179 | } |
692613e5 |
180 | #else |
498ce76b |
181 | bool Image_AlienPixMap::InitTrash (ImgFormat thePixelFormat, |
182 | const Standard_Size theSizeX, |
183 | const Standard_Size theSizeY, |
184 | const Standard_Size theSizeRowBytes) |
185 | { |
692613e5 |
186 | return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes); |
692613e5 |
187 | } |
498ce76b |
188 | #endif |
692613e5 |
189 | |
190 | // ======================================================================= |
3c3131a0 |
191 | // function : InitCopy |
692613e5 |
192 | // purpose : |
193 | // ======================================================================= |
194 | bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy) |
195 | { |
196 | if (&theCopy == this) |
197 | { |
198 | // self-copying disallowed |
199 | return false; |
200 | } |
201 | if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes())) |
202 | { |
203 | return false; |
204 | } |
205 | |
206 | if (myImgFormat == theCopy.Format()) |
207 | { |
208 | if (myData.mySizeRowBytes == theCopy.SizeRowBytes() |
209 | && myData.myTopToDown == theCopy.TopDownInc()) |
210 | { |
211 | // copy with one call |
212 | memcpy (myData.myDataPtr, theCopy.Data(), theCopy.SizeBytes()); |
213 | return true; |
214 | } |
215 | |
216 | // copy row-by-row |
217 | const Standard_Size aRowSizeBytes = (myData.mySizeRowBytes > theCopy.SizeRowBytes()) |
218 | ? theCopy.SizeRowBytes() : myData.mySizeRowBytes; |
219 | for (Standard_Size aRow = 0; aRow < myData.mySizeY; ++aRow) |
220 | { |
221 | memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes); |
222 | } |
223 | return true; |
224 | } |
225 | |
226 | // pixel format conversion required |
227 | Clear(); |
228 | return false; |
229 | } |
230 | |
231 | // ======================================================================= |
232 | // function : Clear |
233 | // purpose : |
234 | // ======================================================================= |
235 | void Image_AlienPixMap::Clear (ImgFormat thePixelFormat) |
236 | { |
237 | Image_PixMap::Clear (thePixelFormat); |
238 | #ifdef HAVE_FREEIMAGE |
239 | if (myLibImage != NULL) |
240 | { |
241 | FreeImage_Unload (myLibImage); |
242 | myLibImage = NULL; |
243 | } |
244 | #endif |
245 | } |
246 | |
247 | // ======================================================================= |
248 | // function : Load |
249 | // purpose : |
250 | // ======================================================================= |
35e08fe8 |
251 | #ifdef HAVE_FREEIMAGE |
692613e5 |
252 | bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath) |
253 | { |
254 | Clear(); |
692613e5 |
255 | FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0); |
256 | if (aFIF == FIF_UNKNOWN) |
257 | { |
258 | // no signature? try to guess the file format from the file extension |
259 | aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString()); |
260 | } |
261 | if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF)) |
262 | { |
263 | // unsupported image format |
264 | return false; |
265 | } |
266 | |
267 | int aLoadFlags = 0; |
268 | if (aFIF == FIF_GIF) |
269 | { |
270 | // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading |
271 | aLoadFlags = GIF_PLAYBACK; |
272 | } |
273 | else if (aFIF == FIF_ICO) |
274 | { |
275 | // convert to 32bpp and create an alpha channel from the AND-mask when loading |
276 | aLoadFlags = ICO_MAKEALPHA; |
277 | } |
278 | |
279 | FIBITMAP* anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags); |
280 | if (anImage == NULL) |
281 | { |
282 | return false; |
283 | } |
284 | |
285 | Image_PixMap::ImgFormat aFormat = convertFromFreeFormat (FreeImage_GetImageType (anImage), |
286 | FreeImage_GetColorType (anImage), |
287 | FreeImage_GetBPP (anImage)); |
288 | if (aFormat == Image_PixMap::ImgUNKNOWN) |
289 | { |
290 | //anImage = FreeImage_ConvertTo24Bits (anImage); |
291 | return false; |
292 | } |
293 | |
294 | Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage), |
295 | FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); |
296 | SetTopDown (false); |
297 | |
298 | // assign image after wrapper initialization (virtual Clear() called inside) |
299 | myLibImage = anImage; |
300 | return true; |
35e08fe8 |
301 | } |
692613e5 |
302 | #else |
35e08fe8 |
303 | bool Image_AlienPixMap::Load (const TCollection_AsciiString&) |
304 | { |
305 | Clear(); |
692613e5 |
306 | return false; |
692613e5 |
307 | } |
35e08fe8 |
308 | #endif |
692613e5 |
309 | |
310 | // ======================================================================= |
311 | // function : savePPM |
312 | // purpose : |
313 | // ======================================================================= |
314 | bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const |
315 | { |
316 | if (IsEmpty()) |
317 | { |
318 | return false; |
319 | } |
320 | |
321 | // Open file |
322 | FILE* aFile = fopen (theFileName.ToCString(), "wb"); |
323 | if (aFile == NULL) |
324 | { |
325 | return false; |
326 | } |
327 | |
328 | // Write header |
329 | fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY()); |
330 | fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n"); |
331 | |
332 | // Write pixel data |
333 | Quantity_Color aColor; |
334 | Quantity_Parameter aDummy; |
335 | Standard_Byte aByte; |
336 | for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) |
337 | { |
338 | for (Standard_Size aCol = 0; aCol < SizeY(); ++aCol) |
339 | { |
340 | // extremely SLOW but universal (implemented for all supported pixel formats) |
6a7d83c4 |
341 | aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow, aDummy); |
692613e5 |
342 | aByte = Standard_Byte(aColor.Red() * 255.0); fwrite (&aByte, 1, 1, aFile); |
343 | aByte = Standard_Byte(aColor.Green() * 255.0); fwrite (&aByte, 1, 1, aFile); |
344 | aByte = Standard_Byte(aColor.Blue() * 255.0); fwrite (&aByte, 1, 1, aFile); |
345 | } |
346 | } |
347 | |
348 | // Close file |
349 | fclose (aFile); |
350 | return true; |
351 | } |
352 | |
353 | // ======================================================================= |
354 | // function : Save |
355 | // purpose : |
356 | // ======================================================================= |
357 | bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName) |
358 | { |
359 | #ifdef HAVE_FREEIMAGE |
360 | if (myLibImage == NULL) |
361 | { |
362 | return false; |
363 | } |
364 | |
365 | FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString()); |
366 | if (anImageFormat == FIF_UNKNOWN) |
367 | { |
368 | std::cerr << "Image_PixMap, image format doesn't supported!\n"; |
369 | return false; |
370 | } |
371 | |
372 | if (IsTopDown()) |
373 | { |
374 | FreeImage_FlipVertical (myLibImage); |
375 | SetTopDown (false); |
376 | } |
377 | |
378 | // FreeImage doesn't provide flexible format convertion API |
379 | // so we should perform multiple convertions in some cases! |
692613e5 |
380 | FIBITMAP* anImageToDump = myLibImage; |
381 | switch (anImageFormat) |
382 | { |
383 | case FIF_PNG: |
384 | case FIF_BMP: |
385 | { |
386 | if (Format() == Image_PixMap::ImgBGR32 |
387 | || Format() == Image_PixMap::ImgRGB32) |
388 | { |
389 | // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF |
390 | Image_PixMapData<Image_ColorRGB32>& aData = Image_PixMap::EditData<Image_ColorRGB32>(); |
391 | for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) |
392 | { |
393 | for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol) |
394 | { |
395 | aData.ChangeValue (aRow, aCol).a_() = 0xFF; |
396 | } |
397 | } |
398 | } |
399 | else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) |
400 | { |
401 | anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); |
402 | } |
403 | break; |
404 | } |
405 | case FIF_GIF: |
406 | { |
407 | FIBITMAP* aTmpBitmap = myLibImage; |
408 | if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) |
409 | { |
410 | aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); |
411 | if (aTmpBitmap == NULL) |
412 | { |
413 | return false; |
414 | } |
415 | } |
416 | |
417 | if (FreeImage_GetBPP (aTmpBitmap) != 24) |
418 | { |
419 | FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap); |
420 | if (aTmpBitmap != myLibImage) |
421 | { |
422 | FreeImage_Unload (aTmpBitmap); |
423 | } |
424 | if (aTmpBitmap24 == NULL) |
425 | { |
426 | return false; |
427 | } |
428 | aTmpBitmap = aTmpBitmap24; |
429 | } |
430 | |
431 | // need convertion to image with pallete (requires 24bit bitmap) |
432 | anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT); |
433 | if (aTmpBitmap != myLibImage) |
434 | { |
435 | FreeImage_Unload (aTmpBitmap); |
436 | } |
437 | break; |
438 | } |
439 | case FIF_EXR: |
440 | { |
441 | if (Format() == Image_PixMap::ImgGray) |
442 | { |
443 | anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT); |
444 | } |
445 | else if (Format() == Image_PixMap::ImgRGBA |
446 | || Format() == Image_PixMap::ImgBGRA) |
447 | { |
448 | anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF); |
449 | } |
450 | else |
451 | { |
452 | FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage); |
453 | if (aImgTypeFI != FIT_RGBF |
454 | && aImgTypeFI != FIT_RGBAF |
455 | && aImgTypeFI != FIT_FLOAT) |
456 | { |
457 | anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF); |
458 | } |
459 | } |
460 | break; |
461 | } |
462 | default: |
463 | { |
464 | if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) |
465 | { |
466 | anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); |
467 | if (anImageToDump == NULL) |
468 | { |
469 | return false; |
470 | } |
471 | } |
472 | |
473 | if (FreeImage_GetBPP (anImageToDump) != 24) |
474 | { |
475 | FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump); |
476 | if (anImageToDump != myLibImage) |
477 | { |
478 | FreeImage_Unload (anImageToDump); |
479 | } |
480 | if (aTmpBitmap24 == NULL) |
481 | { |
482 | return false; |
483 | } |
484 | anImageToDump = aTmpBitmap24; |
485 | } |
486 | break; |
487 | } |
488 | } |
489 | |
490 | if (anImageToDump == NULL) |
491 | { |
492 | return false; |
493 | } |
494 | |
495 | bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE); |
496 | if (anImageToDump != myLibImage) |
497 | { |
498 | FreeImage_Unload (anImageToDump); |
499 | } |
500 | return isSaved; |
501 | #else |
502 | const Standard_Integer aLen = theFileName.Length(); |
503 | if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.') |
29cb310a |
504 | && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 ) |
692613e5 |
505 | { |
506 | return savePPM (theFileName); |
507 | } |
508 | std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n"; |
509 | return savePPM (theFileName); |
510 | #endif |
511 | } |
512 | |
513 | // ======================================================================= |
514 | // function : AdjustGamma |
515 | // purpose : |
516 | // ======================================================================= |
35e08fe8 |
517 | #ifdef HAVE_FREEIMAGE |
692613e5 |
518 | Standard_EXPORT bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr) |
519 | { |
692613e5 |
520 | return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE; |
35e08fe8 |
521 | } |
692613e5 |
522 | #else |
35e08fe8 |
523 | Standard_EXPORT bool Image_AlienPixMap::AdjustGamma (const Standard_Real) |
524 | { |
525 | return false; |
692613e5 |
526 | } |
35e08fe8 |
527 | #endif |