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