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