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 | // ======================================================================= |
132 | bool Image_AlienPixMap::InitWrapper (ImgFormat thePixelFormat, |
133 | Standard_Byte* theDataPtr, |
134 | const Standard_Size theSizeX, |
135 | const Standard_Size theSizeY, |
136 | const Standard_Size theSizeRowBytes) |
137 | { |
138 | Clear(); |
139 | return false; |
140 | } |
141 | |
142 | // ======================================================================= |
143 | // function : InitTrash |
144 | // purpose : |
145 | // ======================================================================= |
146 | bool Image_AlienPixMap::InitTrash (ImgFormat thePixelFormat, |
147 | const Standard_Size theSizeX, |
148 | const Standard_Size theSizeY, |
149 | const Standard_Size theSizeRowBytes) |
150 | { |
151 | Clear(); |
152 | #ifdef HAVE_FREEIMAGE |
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; |
179 | #else |
180 | return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes); |
181 | #endif |
182 | } |
183 | |
184 | // ======================================================================= |
3c3131a0 |
185 | // function : InitCopy |
692613e5 |
186 | // purpose : |
187 | // ======================================================================= |
188 | bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy) |
189 | { |
190 | if (&theCopy == this) |
191 | { |
192 | // self-copying disallowed |
193 | return false; |
194 | } |
195 | if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes())) |
196 | { |
197 | return false; |
198 | } |
199 | |
200 | if (myImgFormat == theCopy.Format()) |
201 | { |
202 | if (myData.mySizeRowBytes == theCopy.SizeRowBytes() |
203 | && myData.myTopToDown == theCopy.TopDownInc()) |
204 | { |
205 | // copy with one call |
206 | memcpy (myData.myDataPtr, theCopy.Data(), theCopy.SizeBytes()); |
207 | return true; |
208 | } |
209 | |
210 | // copy row-by-row |
211 | const Standard_Size aRowSizeBytes = (myData.mySizeRowBytes > theCopy.SizeRowBytes()) |
212 | ? theCopy.SizeRowBytes() : myData.mySizeRowBytes; |
213 | for (Standard_Size aRow = 0; aRow < myData.mySizeY; ++aRow) |
214 | { |
215 | memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes); |
216 | } |
217 | return true; |
218 | } |
219 | |
220 | // pixel format conversion required |
221 | Clear(); |
222 | return false; |
223 | } |
224 | |
225 | // ======================================================================= |
226 | // function : Clear |
227 | // purpose : |
228 | // ======================================================================= |
229 | void Image_AlienPixMap::Clear (ImgFormat thePixelFormat) |
230 | { |
231 | Image_PixMap::Clear (thePixelFormat); |
232 | #ifdef HAVE_FREEIMAGE |
233 | if (myLibImage != NULL) |
234 | { |
235 | FreeImage_Unload (myLibImage); |
236 | myLibImage = NULL; |
237 | } |
238 | #endif |
239 | } |
240 | |
241 | // ======================================================================= |
242 | // function : Load |
243 | // purpose : |
244 | // ======================================================================= |
245 | bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath) |
246 | { |
247 | Clear(); |
248 | #ifdef HAVE_FREEIMAGE |
249 | |
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; |
296 | #else |
297 | return false; |
298 | #endif |
299 | } |
300 | |
301 | // ======================================================================= |
302 | // function : savePPM |
303 | // purpose : |
304 | // ======================================================================= |
305 | bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const |
306 | { |
307 | if (IsEmpty()) |
308 | { |
309 | return false; |
310 | } |
311 | |
312 | // Open file |
313 | FILE* aFile = fopen (theFileName.ToCString(), "wb"); |
314 | if (aFile == NULL) |
315 | { |
316 | return false; |
317 | } |
318 | |
319 | // Write header |
320 | fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY()); |
321 | fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n"); |
322 | |
323 | // Write pixel data |
324 | Quantity_Color aColor; |
325 | Quantity_Parameter aDummy; |
326 | Standard_Byte aByte; |
327 | for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) |
328 | { |
329 | for (Standard_Size aCol = 0; aCol < SizeY(); ++aCol) |
330 | { |
331 | // extremely SLOW but universal (implemented for all supported pixel formats) |
332 | aColor = PixelColor (aCol, aRow, aDummy); |
333 | aByte = Standard_Byte(aColor.Red() * 255.0); fwrite (&aByte, 1, 1, aFile); |
334 | aByte = Standard_Byte(aColor.Green() * 255.0); fwrite (&aByte, 1, 1, aFile); |
335 | aByte = Standard_Byte(aColor.Blue() * 255.0); fwrite (&aByte, 1, 1, aFile); |
336 | } |
337 | } |
338 | |
339 | // Close file |
340 | fclose (aFile); |
341 | return true; |
342 | } |
343 | |
344 | // ======================================================================= |
345 | // function : Save |
346 | // purpose : |
347 | // ======================================================================= |
348 | bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName) |
349 | { |
350 | #ifdef HAVE_FREEIMAGE |
351 | if (myLibImage == NULL) |
352 | { |
353 | return false; |
354 | } |
355 | |
356 | FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString()); |
357 | if (anImageFormat == FIF_UNKNOWN) |
358 | { |
359 | std::cerr << "Image_PixMap, image format doesn't supported!\n"; |
360 | return false; |
361 | } |
362 | |
363 | if (IsTopDown()) |
364 | { |
365 | FreeImage_FlipVertical (myLibImage); |
366 | SetTopDown (false); |
367 | } |
368 | |
369 | // FreeImage doesn't provide flexible format convertion API |
370 | // so we should perform multiple convertions in some cases! |
692613e5 |
371 | FIBITMAP* anImageToDump = myLibImage; |
372 | switch (anImageFormat) |
373 | { |
374 | case FIF_PNG: |
375 | case FIF_BMP: |
376 | { |
377 | if (Format() == Image_PixMap::ImgBGR32 |
378 | || Format() == Image_PixMap::ImgRGB32) |
379 | { |
380 | // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF |
381 | Image_PixMapData<Image_ColorRGB32>& aData = Image_PixMap::EditData<Image_ColorRGB32>(); |
382 | for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) |
383 | { |
384 | for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol) |
385 | { |
386 | aData.ChangeValue (aRow, aCol).a_() = 0xFF; |
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) == '.') |
495 | && TCollection_AsciiString::ISSIMILAR (theFileName.SubString (aLen - 2, aLen), "ppm")) |
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 | // ======================================================================= |
508 | Standard_EXPORT bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr) |
509 | { |
510 | #ifdef HAVE_FREEIMAGE |
511 | return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE; |
512 | #else |
513 | return false; |
514 | #endif |
515 | } |