0028876: Tests, Image_Diff - the image difference is unavailable for test case bugs...
[occt.git] / src / Image / Image_PixMap.cxx
1 // Created on: 2010-07-18
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2010-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Image_PixMap.hxx>
17 #include <NCollection_AlignedAllocator.hxx>
18 #include <Standard_ProgramError.hxx>
19
20 #include <algorithm>
21
22 IMPLEMENT_STANDARD_RTTIEXT(Image_PixMap,Standard_Transient)
23
24 // =======================================================================
25 // function : Image_PixMap
26 // purpose  :
27 // =======================================================================
28 Image_PixMap::Image_PixMap()
29 : myImgFormat (Image_Format_Gray)
30 {
31   //
32 }
33
34 // =======================================================================
35 // function : ~Image_PixMap
36 // purpose  :
37 // =======================================================================
38 Image_PixMap::~Image_PixMap()
39 {
40   Clear();
41 }
42
43 Standard_Size Image_PixMap::SizePixelBytes (const Image_Format thePixelFormat)
44 {
45   switch (thePixelFormat)
46   {
47     case Image_Format_GrayF:
48     case Image_Format_AlphaF:
49       return sizeof(float);
50     case Image_Format_RGBAF:
51     case Image_Format_BGRAF:
52       return sizeof(float) * 4;
53     case Image_Format_RGBF:
54     case Image_Format_BGRF:
55       return sizeof(float) * 3;
56     case Image_Format_RGBA:
57     case Image_Format_BGRA:
58       return 4;
59     case Image_Format_RGB32:
60     case Image_Format_BGR32:
61       return 4;
62     case Image_Format_RGB:
63     case Image_Format_BGR:
64       return 3;
65     case Image_Format_Gray:
66     case Image_Format_Alpha:
67       return 1;
68     case Image_Format_UNKNOWN:
69       return 1;
70   }
71   return 1;
72 }
73
74 // =======================================================================
75 // function : SetFormat
76 // purpose  :
77 // =======================================================================
78 void Image_PixMap::SetFormat (Image_Format thePixelFormat)
79 {
80   if (myImgFormat == thePixelFormat)
81   {
82     return;
83   }
84
85   if (!IsEmpty()
86     && SizePixelBytes (myImgFormat) != SizePixelBytes (thePixelFormat))
87   {
88     throw Standard_ProgramError("Image_PixMap::SetFormat() - incompatible pixel format");
89     return;
90   }
91
92   myImgFormat = thePixelFormat;
93 }
94
95 // =======================================================================
96 // function : InitWrapper
97 // purpose  :
98 // =======================================================================
99 bool Image_PixMap::InitWrapper (Image_Format        thePixelFormat,
100                                 Standard_Byte*      theDataPtr,
101                                 const Standard_Size theSizeX,
102                                 const Standard_Size theSizeY,
103                                 const Standard_Size theSizeRowBytes)
104 {
105   Clear();
106   myImgFormat = thePixelFormat;
107   if ((theSizeX == 0) || (theSizeY == 0) || (theDataPtr == NULL))
108   {
109     return false;
110   }
111
112   Handle(NCollection_BaseAllocator) anEmptyAlloc;
113   myData.Init (anEmptyAlloc, Image_PixMap::SizePixelBytes (thePixelFormat),
114                theSizeX, theSizeY, theSizeRowBytes, theDataPtr);
115   return true;
116 }
117
118 // =======================================================================
119 // function : InitTrash
120 // purpose  :
121 // =======================================================================
122 bool Image_PixMap::InitTrash (Image_Format        thePixelFormat,
123                               const Standard_Size theSizeX,
124                               const Standard_Size theSizeY,
125                               const Standard_Size theSizeRowBytes)
126 {
127   Clear();
128   myImgFormat = thePixelFormat;
129   if ((theSizeX == 0) || (theSizeY == 0))
130   {
131     return false;
132   }
133
134   // use argument only if it greater
135   const Standard_Size aSizeRowBytes = std::max (theSizeRowBytes, theSizeX * SizePixelBytes (thePixelFormat));
136   Handle(NCollection_BaseAllocator) anAlloc = new NCollection_AlignedAllocator (16);
137   myData.Init (anAlloc, Image_PixMap::SizePixelBytes (thePixelFormat),
138                theSizeX, theSizeY, aSizeRowBytes, NULL);
139   return !myData.IsEmpty();
140 }
141
142 // =======================================================================
143 // function : InitZero
144 // purpose  :
145 // =======================================================================
146 bool Image_PixMap::InitZero (Image_Format        thePixelFormat,
147                              const Standard_Size theSizeX,
148                              const Standard_Size theSizeY,
149                              const Standard_Size theSizeRowBytes,
150                              const Standard_Byte theValue)
151 {
152   if (!InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes))
153   {
154     return false;
155   }
156   memset (myData.ChangeData(), (int )theValue, SizeBytes());
157   return true;
158 }
159
160 // =======================================================================
161 // function : InitCopy
162 // purpose  :
163 // =======================================================================
164 bool Image_PixMap::InitCopy (const Image_PixMap& theCopy)
165 {
166   if (&theCopy == this)
167   {
168     // self-copying disallowed
169     return false;
170   }
171   if (InitTrash (theCopy.myImgFormat, theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes()))
172   {
173     memcpy (myData.ChangeData(), theCopy.myData.Data(), theCopy.SizeBytes());
174     return true;
175   }
176   return false;
177 }
178
179 // =======================================================================
180 // function : Clear
181 // purpose  :
182 // =======================================================================
183 void Image_PixMap::Clear()
184 {
185   Handle(NCollection_BaseAllocator) anEmptyAlloc;
186   myData.Init (anEmptyAlloc, Image_PixMap::SizePixelBytes (myImgFormat),
187                0, 0, 0, NULL);
188 }
189
190 // =======================================================================
191 // function : PixelColor
192 // purpose  :
193 // =======================================================================
194 Quantity_ColorRGBA Image_PixMap::PixelColor (const Standard_Integer theX,
195                                              const Standard_Integer theY) const
196 {
197   if (IsEmpty()
198    || theX < 0 || (Standard_Size )theX >= SizeX()
199    || theY < 0 || (Standard_Size )theY >= SizeY())
200   {
201     return Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 0.0f); // transparent
202   }
203
204   switch (myImgFormat)
205   {
206     case Image_Format_GrayF:
207     {
208       const Standard_ShortReal& aPixel = Value<Standard_ShortReal> (theY, theX);
209       return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel, aPixel, aPixel, 1.0f)); // opaque
210     }
211     case Image_Format_AlphaF:
212     {
213       const Standard_ShortReal& aPixel = Value<Standard_ShortReal> (theY, theX);
214       return Quantity_ColorRGBA (NCollection_Vec4<float> (1.0f, 1.0f, 1.0f, aPixel));
215     }
216     case Image_Format_RGBAF:
217     {
218       const Image_ColorRGBAF& aPixel = Value<Image_ColorRGBAF> (theY, theX);
219       return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), aPixel.a()));
220     }
221     case Image_Format_BGRAF:
222     {    
223       const Image_ColorBGRAF& aPixel = Value<Image_ColorBGRAF> (theY, theX);
224       return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), aPixel.a()));
225     }
226     case Image_Format_RGBF:
227     {
228       const Image_ColorRGBF& aPixel = Value<Image_ColorRGBF> (theY, theX);
229       return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), 1.0f)); // opaque
230     }
231     case Image_Format_BGRF:
232     {
233       const Image_ColorBGRF& aPixel = Value<Image_ColorBGRF> (theY, theX);
234       return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), 1.0f)); // opaque
235     }
236     case Image_Format_RGBA:
237     {
238       const Image_ColorRGBA& aPixel = Value<Image_ColorRGBA> (theY, theX);
239       return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, float(aPixel.a()) / 255.0f);
240     }
241     case Image_Format_BGRA:
242     {
243       const Image_ColorBGRA& aPixel = Value<Image_ColorBGRA> (theY, theX);
244       return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, float(aPixel.a()) / 255.0f);
245     }
246     case Image_Format_RGB32:
247     {
248       const Image_ColorRGB32& aPixel = Value<Image_ColorRGB32> (theY, theX);
249       return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
250     }
251     case Image_Format_BGR32:
252     {
253       const Image_ColorBGR32& aPixel = Value<Image_ColorBGR32> (theY, theX);
254       return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
255     }
256     case Image_Format_RGB:
257     {
258       const Image_ColorRGB& aPixel = Value<Image_ColorRGB> (theY, theX);
259       return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
260     }
261     case Image_Format_BGR:
262     {
263       const Image_ColorBGR& aPixel = Value<Image_ColorBGR> (theY, theX);
264       return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
265     }
266     case Image_Format_Gray:
267     {
268       const Standard_Byte& aPixel = Value<Standard_Byte> (theY, theX);
269       return Quantity_ColorRGBA (float(aPixel) / 255.0f, float(aPixel) / 255.0f, float(aPixel) / 255.0f, 1.0f); // opaque
270     }
271     case Image_Format_Alpha:
272     {
273       const Standard_Byte& aPixel = Value<Standard_Byte> (theY, theX);
274       return Quantity_ColorRGBA (1.0f, 1.0f, 1.0f, float(aPixel) / 255.0f);
275     }
276     case Image_Format_UNKNOWN:
277     {
278       break;
279     }
280   }
281
282   // unsupported image type
283   return Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 0.0f); // transparent
284 }
285
286 // =======================================================================
287 // function : SetPixelColor
288 // purpose  :
289 // =======================================================================
290 void Image_PixMap::SetPixelColor (const Standard_Integer theX,
291                                   const Standard_Integer theY,
292                                   const Quantity_ColorRGBA& theColor)
293 {
294   if (IsEmpty()
295    || theX < 0 || Standard_Size(theX) >= SizeX()
296    || theY < 0 || Standard_Size(theY) >= SizeY())
297   {
298     return;
299   }
300
301   const NCollection_Vec4<float>& aColor = theColor;
302   switch (myImgFormat)
303   {
304     case Image_Format_GrayF:
305     {
306       ChangeValue<Standard_ShortReal> (theY, theX) = aColor.r();
307       return;
308     }
309     case Image_Format_AlphaF:
310     {
311       ChangeValue<Standard_ShortReal> (theY, theX) = aColor.a();
312       return;
313     }
314     case Image_Format_RGBAF:
315     {
316       Image_ColorRGBAF& aPixel = ChangeValue<Image_ColorRGBAF> (theY, theX);
317       aPixel.r() = aColor.r();
318       aPixel.g() = aColor.g();
319       aPixel.b() = aColor.b();
320       aPixel.a() = aColor.a();
321       return;
322     }
323     case Image_Format_BGRAF:
324     {
325       Image_ColorBGRAF& aPixel = ChangeValue<Image_ColorBGRAF> (theY, theX);
326       aPixel.r() = aColor.r();
327       aPixel.g() = aColor.g();
328       aPixel.b() = aColor.b();
329       aPixel.a() = aColor.a();
330       return;
331     }
332     case Image_Format_RGBF:
333     {
334       Image_ColorRGBF& aPixel = ChangeValue<Image_ColorRGBF> (theY, theX);
335       aPixel.r() = aColor.r();
336       aPixel.g() = aColor.g();
337       aPixel.b() = aColor.b();
338       return;
339     }
340     case Image_Format_BGRF:
341     {
342       Image_ColorBGRF& aPixel = ChangeValue<Image_ColorBGRF> (theY, theX);
343       aPixel.r() = aColor.r();
344       aPixel.g() = aColor.g();
345       aPixel.b() = aColor.b();
346       return;
347     }
348     case Image_Format_RGBA:
349     {
350       Image_ColorRGBA& aPixel = ChangeValue<Image_ColorRGBA> (theY, theX);
351       aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
352       aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
353       aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
354       aPixel.a() = Standard_Byte(aColor.a() * 255.0f);
355       return;
356     }
357     case Image_Format_BGRA:
358     {
359       Image_ColorBGRA& aPixel = ChangeValue<Image_ColorBGRA> (theY, theX);
360       aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
361       aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
362       aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
363       aPixel.a() = Standard_Byte(aColor.a() * 255.0f);
364       return;
365     }
366     case Image_Format_RGB32:
367     {
368       Image_ColorRGB32& aPixel = ChangeValue<Image_ColorRGB32> (theY, theX);
369       aPixel.r()  = Standard_Byte(aColor.r() * 255.0f);
370       aPixel.g()  = Standard_Byte(aColor.g() * 255.0f);
371       aPixel.b()  = Standard_Byte(aColor.b() * 255.0f);
372       aPixel.a_() = 255;
373       return;
374     }
375     case Image_Format_BGR32:
376     {
377       Image_ColorBGR32& aPixel = ChangeValue<Image_ColorBGR32> (theY, theX);
378       aPixel.r()  = Standard_Byte(aColor.r() * 255.0f);
379       aPixel.g()  = Standard_Byte(aColor.g() * 255.0f);
380       aPixel.b()  = Standard_Byte(aColor.b() * 255.0f);
381       aPixel.a_() = 255;
382       return;
383     }
384     case Image_Format_RGB:
385     {
386       Image_ColorRGB& aPixel = ChangeValue<Image_ColorRGB> (theY, theX);
387       aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
388       aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
389       aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
390       return;
391     }
392     case Image_Format_BGR:
393     {
394       Image_ColorBGR& aPixel = ChangeValue<Image_ColorBGR> (theY, theX);
395       aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
396       aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
397       aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
398       return;
399     }
400     case Image_Format_Gray:
401     {
402       ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(aColor.r() * 255.0f);
403       return;
404     }
405     case Image_Format_Alpha:
406     {
407       ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(aColor.a() * 255.0f);
408       return;
409     }
410     case Image_Format_UNKNOWN:
411     {
412       return;
413     }
414   }
415 }
416
417 // =======================================================================
418 // function : SwapRgbaBgra
419 // purpose  :
420 // =======================================================================
421 bool Image_PixMap::SwapRgbaBgra (Image_PixMap& theImage)
422 {
423   switch (theImage.Format())
424   {
425     case Image_Format_BGR32:
426     case Image_Format_RGB32:
427     case Image_Format_BGRA:
428     case Image_Format_RGBA:
429     {
430       const bool toResetAlpha = theImage.Format() == Image_Format_BGR32
431                              || theImage.Format() == Image_Format_RGB32;
432       for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
433       {
434         for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
435         {
436           Image_ColorRGBA& aPixel     = theImage.ChangeValue<Image_ColorRGBA> (aRow, aCol);
437           Image_ColorBGRA  aPixelCopy = theImage.Value      <Image_ColorBGRA> (aRow, aCol);
438           aPixel.r() = aPixelCopy.r();
439           aPixel.g() = aPixelCopy.g();
440           aPixel.b() = aPixelCopy.b();
441           if (toResetAlpha)
442           {
443             aPixel.a() = 255;
444           }
445         }
446       }
447       return true;
448     }
449     case Image_Format_BGR:
450     case Image_Format_RGB:
451     {
452       for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
453       {
454         for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
455         {
456           Image_ColorRGB& aPixel     = theImage.ChangeValue<Image_ColorRGB> (aRow, aCol);
457           Image_ColorBGR  aPixelCopy = theImage.Value      <Image_ColorBGR> (aRow, aCol);
458           aPixel.r() = aPixelCopy.r();
459           aPixel.g() = aPixelCopy.g();
460           aPixel.b() = aPixelCopy.b();
461         }
462       }
463       return true;
464     }
465     case Image_Format_BGRF:
466     case Image_Format_RGBF:
467     case Image_Format_BGRAF:
468     case Image_Format_RGBAF:
469     {
470       for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
471       {
472         for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
473         {
474           Image_ColorRGBF& aPixel     = theImage.ChangeValue<Image_ColorRGBF> (aRow, aCol);
475           Image_ColorBGRF  aPixelCopy = theImage.Value      <Image_ColorBGRF> (aRow, aCol);
476           aPixel.r() = aPixelCopy.r();
477           aPixel.g() = aPixelCopy.g();
478           aPixel.b() = aPixelCopy.b();
479         }
480       }
481       return true;
482     }
483     default: return false;
484   }
485 }
486
487 // =======================================================================
488 // function : ToBlackWhite
489 // purpose  :
490 // =======================================================================
491 void Image_PixMap::ToBlackWhite (Image_PixMap& theImage)
492 {
493   switch (theImage.Format())
494   {
495     case Image_Format_Gray:
496     case Image_Format_Alpha:
497     {
498       for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
499       {
500         for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
501         {
502           unsigned char& aPixel = theImage.ChangeValue<unsigned char> (aRow, aCol);
503           if (aPixel != 0)
504           {
505             aPixel = 255;
506           }
507         }
508       }
509       break;
510     }
511     case Image_Format_RGB:
512     case Image_Format_BGR:
513     case Image_Format_RGB32:
514     case Image_Format_BGR32:
515     case Image_Format_RGBA:
516     case Image_Format_BGRA:
517     {
518       const NCollection_Vec3<unsigned char> aWhite24 (255, 255, 255);
519       for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
520       {
521         for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
522         {
523           NCollection_Vec3<unsigned char>& aPixel = theImage.ChangeValue< NCollection_Vec3<unsigned char> > (aRow, aCol);
524           if (aPixel[0] != 0
525            || aPixel[1] != 0
526            || aPixel[2] != 0)
527           {
528             aPixel = aWhite24;
529           }
530         }
531       }
532       break;
533     }
534     default:
535     {
536       const Quantity_ColorRGBA aWhiteRgba (1.0f, 1.0f, 1.0f, 1.0f);
537       for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
538       {
539         for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
540         {
541           const Quantity_ColorRGBA       aPixelRgba = theImage.PixelColor (Standard_Integer(aCol), Standard_Integer(aRow));
542           const NCollection_Vec4<float>& aPixel     = aPixelRgba;
543           if (aPixel[0] != 0.0f
544            || aPixel[1] != 0.0f
545            || aPixel[2] != 0.0f)
546           {
547             theImage.SetPixelColor (int(aCol), int(aRow), aWhiteRgba);
548           }
549         }
550       }
551       break;
552     }
553   }
554 }