0028876: Tests, Image_Diff - the image difference is unavailable for test case bugs...
authorkgv <kgv@opencascade.com>
Mon, 3 Jul 2017 09:27:08 +0000 (12:27 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 6 Jul 2017 09:45:37 +0000 (12:45 +0300)
Quantity_ColorRGBA - added method SetValues().
Image_PixMap::PixelColor() now returns Quantity_ColorRGBA instead of Quantity_Color.
Image_PixMap::SetPixelColor() now takes Quantity_ColorRGBA instead of NCollection_Vec4<float>.

Image_Diff has been improved to support Image_Format_Gray.
Image_Diff::SaveDiffImage() now saves image difference
in Image_Format_Gray format to reduce size of image file.

Image_Diff now uses TColStd_HPackedMapOfInteger instead of
TColStd_MapOfInteger with manual memory allocation.

13 files changed:
dox/dev_guides/upgrade/upgrade.md
src/Graphic3d/Graphic3d_MarkerImage.cxx
src/Image/Image_AlienPixMap.cxx
src/Image/Image_Diff.cxx
src/Image/Image_Diff.hxx
src/Image/Image_PixMap.cxx
src/Image/Image_PixMap.hxx
src/NCollection/NCollection_Vec2.hxx
src/NCollection/NCollection_Vec3.hxx
src/NCollection/NCollection_Vec4.hxx
src/Quantity/Quantity_ColorRGBA.hxx
src/StdSelect/StdSelect_ViewerSelector3d.cxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx

index ce24c92..4300467 100644 (file)
@@ -1252,6 +1252,7 @@ In most cases this change should be transparent, however applications implementi
 * Enumeration *Image_PixMap::ImgFormat*, previously declared as nested enumeration within class *Image_PixMap*, has been moved to global namespace as *Image_Format* following OCCT coding rules.
   The enumeration values have suffix Image_Format_ and preserve previous name scheme for easy renaming of old values - e.g. Image_PixMap::ImgGray become Image_Format_Gray.
   Old definitions are preserved as depreacated aliases to the new ones;
+* Methods *Image_PixMap::PixelColor()* and *Image_PixMap::SetPixelColor()* now take/return Quantity_ColorRGBA instead of Quantity_Color/NCollection_Vec4.
 * The method BOPAlgo_Builder::Origins() returns BOPCol_DataMapOfShapeListOfShape instead of BOPCol_DataMapOfShapeShape.
 * The methods BOPDS_DS::IsToSort(const Handle(BOPDS_CommonBlock)&, Standard_Integer&) and BOPDS_DS::SortPaveBlocks(const Handle(BOPDS_CommonBlock)&) have been removed. The sorting is now performed during the addition of the Pave Blocks into Common Block.
 * The methods BOPAlgo_Tools::MakeBlocks() and BOPAlgo_Tools::MakeBlocksCnx() have been replaced with the single template method BOPAlgo_Tools::MakeBlocks(). The chains of connected elements are now stored into the list of list instead of data map.
index 8063a1a..a8b51dc 100755 (executable)
@@ -90,21 +90,15 @@ Handle(TColStd_HArray1OfByte) Graphic3d_MarkerImage::GetBitMapArray (const Stand
   {
     for (Standard_Integer aColumn = 0; aColumn < aWidth; aColumn++)
     {
-      Standard_Real anAlphaValue;
-      Quantity_Color aColor = myImage->PixelColor (aColumn, aRow, anAlphaValue);
+      const Quantity_ColorRGBA aColor = myImage->PixelColor (aColumn, aRow);
       Standard_Boolean aBitOn = Standard_False;
-
-      if (myImage->Format() == Image_Format_Alpha)
-      {
-        aBitOn = anAlphaValue > theAlphaValue;
-      }
-      else if (myImage->Format() == Image_Format_Gray)
+      if (myImage->Format() == Image_Format_Gray)
       {
-        aBitOn = aColor.Red() > theAlphaValue;
+        aBitOn = aColor.GetRGB().Red() > theAlphaValue;
       }
-      else
+      else //if (myImage->Format() == Image_Format_Alpha)
       {
-        aBitOn = anAlphaValue > theAlphaValue;
+        aBitOn = aColor.Alpha() > theAlphaValue;
       }
 
       Standard_Integer anIndex = aNumOfBytesInRow * aRow + aColumn / 8;
@@ -179,14 +173,13 @@ const Handle(Image_PixMap)& Graphic3d_MarkerImage::GetImageAlpha()
       myImageAlpha = new Image_PixMap();
       myImageAlpha->InitZero (Image_Format_Alpha, myImage->Width(), myImage->Height());
       myImageAlpha->SetTopDown (Standard_False);
-      Standard_Real anAlpha;
       for (Standard_Size aRowIter = 0; aRowIter < myImage->Height(); aRowIter++)
       {
         Standard_Byte* anImageRow = myImageAlpha->ChangeRow (aRowIter);
         for (Standard_Size aColumnIter = 0; aColumnIter < myImage->Width(); aColumnIter++)
         {
-          myImage->PixelColor ((Standard_Integer)aColumnIter, (Standard_Integer)aRowIter, anAlpha);
-          anImageRow[aColumnIter] = Standard_Byte (255.0 * anAlpha);
+          const Quantity_ColorRGBA aColor = myImage->PixelColor ((Standard_Integer)aColumnIter, (Standard_Integer)aRowIter);
+          anImageRow[aColumnIter] = Standard_Byte (255.0 * aColor.Alpha());
         }
       }
     }
index cb795ac..bf00775 100644 (file)
@@ -349,18 +349,16 @@ bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) con
   fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n");
 
   // Write pixel data
-  Quantity_Color aColor;
-  Standard_Real aDummy;
   Standard_Byte aByte;
   for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
   {
     for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
     {
       // extremely SLOW but universal (implemented for all supported pixel formats)
-      aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow, aDummy);
-      aByte = Standard_Byte(aColor.Red() * 255.0);   fwrite (&aByte, 1, 1, aFile);
-      aByte = Standard_Byte(aColor.Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
-      aByte = Standard_Byte(aColor.Blue() * 255.0);  fwrite (&aByte, 1, 1, aFile);
+      const Quantity_ColorRGBA aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow);
+      aByte = Standard_Byte(aColor.GetRGB().Red()   * 255.0); fwrite (&aByte, 1, 1, aFile);
+      aByte = Standard_Byte(aColor.GetRGB().Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
+      aByte = Standard_Byte(aColor.GetRGB().Blue()  * 255.0); fwrite (&aByte, 1, 1, aFile);
     }
   }
 
index 6d6f0fb..a1c5183 100644 (file)
 // commercial license or contractual agreement.
 
 #include <Image_Diff.hxx>
-#include <Image_AlienPixMap.hxx>
 
-#include <TColStd_MapIteratorOfMapOfInteger.hxx>
+#include <Image_AlienPixMap.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
 
 #include <cstdlib>
 
-
 IMPLEMENT_STANDARD_RTTIEXT(Image_Diff,Standard_Transient)
 
-//! POD structure for packed RGB color value (3 bytes)
-struct Image_ColorXXX24
-{
-  Standard_Byte v[3];
-  typedef Standard_Byte ComponentType_t;         //!< Component type
-  static Standard_Integer Length() { return 3; } //!< Returns the number of components
-};
-
-inline Image_ColorXXX24 operator- (const Image_ColorXXX24& theA,
-                                   const Image_ColorXXX24& theB)
-{
-  return Image_ColorSub3 (theA, theB);
-}
-
-//! Dot squared for difference of two colors
-inline Standard_Integer dotSquared (const Image_ColorXXX24& theColor)
-{
-  // explicitly convert to integer
-  const Standard_Integer r = theColor.v[0];
-  const Standard_Integer g = theColor.v[1];
-  const Standard_Integer b = theColor.v[2];
-  return r * r + g * g + b * b;
-}
-
-//! @return true if pixel is black
-inline bool isBlack (const Image_ColorXXX24& theColor)
-{
-  return theColor.v[0] == 0
-      && theColor.v[1] == 0
-      && theColor.v[2] == 0;
-}
-
-//! Converts a pixel position (row, column) to one integer value
-inline Standard_Size pixel2Int (const Standard_Size aRow,
-                                const Standard_Size aCol)
-{
-  return aCol + (aRow << 15);
-}
-
-//! Converts an integer value to pixel coordinates (row, column)
-inline void int2Pixel (const Standard_Size theValue,
-                       Standard_Size&      theRow,
-                       Standard_Size&      theCol)
-{
-  theRow = (theValue >> 15);
-  theCol = theValue - (theRow << 15);
-}
-
 namespace
 {
 
-  inline ptrdiff_t getAbs (const ptrdiff_t theValue)
+  //! POD structure for packed RGB color value (3 bytes)
+  struct Image_ColorXXX24
   {
-    return theValue >= 0 ? theValue : -theValue;
-  }
+    Standard_Byte v[3];
+    typedef Standard_Byte ComponentType_t;         //!< Component type
+    static Standard_Integer Length() { return 3; } //!< Returns the number of components
+  };
 
-  static const Standard_Size NEIGHBOR_PIXELS_NB = 8;
-  static struct
+  static Image_ColorXXX24 operator- (const Image_ColorXXX24& theA,
+                                     const Image_ColorXXX24& theB)
   {
-    Standard_Integer row_inc;
-    Standard_Integer col_inc;
+    return Image_ColorSub3 (theA, theB);
+  }
 
-    inline Standard_Size pixel2Int (const Standard_Size theRowCenter,
-                                    const Standard_Size theColCenter) const
-    {
-      return ::pixel2Int (theRowCenter + Standard_Size(row_inc),
-                          theColCenter + Standard_Size(col_inc));
-    }
+  //! Dot squared for difference of two colors
+  static Standard_Integer dotSquared (const Image_ColorXXX24& theColor)
+  {
+    // explicitly convert to integer
+    const Standard_Integer r = theColor.v[0];
+    const Standard_Integer g = theColor.v[1];
+    const Standard_Integer b = theColor.v[2];
+    return r * r + g * g + b * b;
+  }
 
-    inline bool isBlack (const Image_PixMap& theData,
-                         const Standard_Size theRowCenter,
-                         const Standard_Size theColCenter) const
-    {
-      return ::isBlack (theData.Value<Image_ColorXXX24> (theRowCenter + Standard_Size(row_inc),
-                                                         theColCenter + Standard_Size(col_inc)));
-    }
+  //! Number of neighbor pixels.
+  static const Standard_Size Image_Diff_NbOfNeighborPixels = 8;
 
-    inline bool isValid (const Image_PixMap& theData,
-                         const Standard_Size theRowCenter,
-                         const Standard_Size theColCenter) const
-    {
-      const Standard_Size aRow = theRowCenter + Standard_Size(row_inc);
-      const Standard_Size aCol = theColCenter + Standard_Size(col_inc);
-      return aRow < theData.SizeX()  // this unsigned math checks Standard_Size(-1) at-once
-          && aCol < theData.SizeY();
-    }
-  }
-  const NEIGHBOR_PIXELS[NEIGHBOR_PIXELS_NB] =
+  //! List of neighbor pixels (offsets).
+  static const int Image_Diff_NEIGHBOR_PIXELS[Image_Diff_NbOfNeighborPixels][2] =
   {
-    {-1, -1}, {-1,  0}, {-1,  1},
-    { 0, -1},           { 0,  1},
-    { 1, -1}, { 1,  0}, { 1,  1}
+    {-1, -1}, {0, -1}, {1, -1},
+    {-1,  0},          {1,  0},
+    {-1,  1}, {0,  1}, {1,  1}
   };
 
-  static bool isSupportedFormat (const Image_Format theFormat)
+  //! @return true if pixel is black
+  static bool isBlackPixel (const Image_PixMap& theData, Standard_Size theY, Standard_Size theX)
   {
-    return theFormat == Image_Format_RGB
-        || theFormat == Image_Format_BGR
-        || theFormat == Image_Format_RGB32
-        || theFormat == Image_Format_BGR32
-        || theFormat == Image_Format_RGBA
-        || theFormat == Image_Format_BGRA;
+    switch (theData.Format())
+    {
+      case Image_Format_Gray:
+      case Image_Format_Alpha:
+      {
+        return theData.Value<unsigned char> (theY, theX) == 0;
+      }
+      case Image_Format_RGB:
+      case Image_Format_BGR:
+      case Image_Format_RGB32:
+      case Image_Format_BGR32:
+      case Image_Format_RGBA:
+      case Image_Format_BGRA:
+      {
+        const Image_ColorXXX24& aColor = theData.Value<Image_ColorXXX24> (theY, theX);
+        return aColor.v[0] == 0
+            && aColor.v[1] == 0
+            && aColor.v[2] == 0;
+      }
+      default:
+      {
+        const Quantity_ColorRGBA aPixelRgba = theData.PixelColor ((int)theY, (int)theX);
+        const NCollection_Vec4<float>& aPixel = aPixelRgba;
+        return aPixel.r() == 0.0f
+            && aPixel.g() == 0.0f
+            && aPixel.b() == 0.0f;
+      }
+    }
   }
 
-} // anonymous namespace
+}
 
 // =======================================================================
 // function : Image_Diff
@@ -167,56 +135,26 @@ Standard_Boolean Image_Diff::Init (const Handle(Image_PixMap)& theImageRef,
    || theImageRef->SizeY()   != theImageNew->SizeY()
    || theImageRef->Format()  != theImageNew->Format())
   {
-#ifdef OCCT_DEBUG
-    std::cerr << "Images has different format or dimensions\n";
-#endif
-    return Standard_False;
-  }
-  else if (!isSupportedFormat (theImageRef->Format()))
-  {
-#ifdef OCCT_DEBUG
-    std::cerr << "Images has unsupported pixel format\n";
-#endif
+    Message::DefaultMessenger()->Send ("Error: Images have different format or dimensions", Message_Fail);
     return Standard_False;
   }
   else if (theImageRef->SizeX() >= 0xFFFF
         || theImageRef->SizeY() >= 0xFFFF)
   {
-#ifdef OCCT_DEBUG
-    std::cerr << "Image too large\n";
-#endif
+    Message::DefaultMessenger()->Send ("Error: Images are too large", Message_Fail);
     return Standard_False;
   }
 
   myImageRef = theImageRef;
   myImageNew = theImageNew;
-
   if (theToBlackWhite)
   {
-    // Convert the images to white/black
-    const Image_ColorXXX24 aWhite = {{255, 255, 255}};
-    for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
-    {
-      for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
-      {
-        Image_ColorXXX24& aPixel1 = myImageRef->ChangeValue<Image_ColorXXX24> (aRow, aCol);
-        if (!isBlack (aPixel1))
-        {
-          aPixel1 = aWhite;
-        }
-        Image_ColorXXX24& aPixel2 = myImageNew->ChangeValue<Image_ColorXXX24> (aRow, aCol);
-        if (!isBlack (aPixel2))
-        {
-          aPixel2 = aWhite;
-        }
-      }
-    }
+    Image_PixMap::ToBlackWhite (*myImageRef);
+    Image_PixMap::ToBlackWhite (*myImageNew);
   }
-
   return Standard_True;
 }
 
-
 // =======================================================================
 // function : Init
 // purpose  :
@@ -230,51 +168,13 @@ Standard_Boolean Image_Diff::Init (const TCollection_AsciiString& theImgPathRef,
   if (!anImgRef->Load (theImgPathRef)
    || !anImgNew->Load (theImgPathNew))
   {
-#ifdef OCCT_DEBUG
-    std::cerr << "Failed to load image(s) file(s)\n";
-#endif
+    Message::DefaultMessenger()->Send ("Error: Failed to load image(s) file(s)", Message_Fail);
     return Standard_False;
   }
   return Init (anImgRef, anImgNew, theToBlackWhite);
 }
 
 // =======================================================================
-// function : SetColorTolerance
-// purpose  :
-// =======================================================================
-void Image_Diff::SetColorTolerance (const Standard_Real theTolerance)
-{
-  myColorTolerance = theTolerance;
-}
-
-// =======================================================================
-// function : ColorTolerance
-// purpose  :
-// =======================================================================
-Standard_Real Image_Diff::ColorTolerance() const
-{
-  return myColorTolerance;
-}
-
-// =======================================================================
-// function : SetBorderFilterOn
-// purpose  :
-// =======================================================================
-void Image_Diff::SetBorderFilterOn (const Standard_Boolean theToIgnore)
-{
-  myIsBorderFilterOn = theToIgnore;
-}
-
-// =======================================================================
-// function : IsBorderFilterOn
-// purpose  :
-// =======================================================================
-Standard_Boolean Image_Diff::IsBorderFilterOn() const
-{
-  return myIsBorderFilterOn;
-}
-
-// =======================================================================
 // function : Compare
 // purpose  :
 // =======================================================================
@@ -289,38 +189,94 @@ Standard_Integer Image_Diff::Compare()
     return -1;
   }
 
-  // first check if images are exactly teh same
-  if (! memcmp (myImageNew->Data(), myImageRef->Data(), myImageRef->SizeBytes()))
+  // first check if images are exactly the same
+  if (myImageNew->SizeBytes() == myImageRef->SizeBytes()
+   && memcmp (myImageNew->Data(), myImageRef->Data(), myImageRef->SizeBytes()) == 0)
   {
     return 0;
   }
 
-  // Tolerance of comparison operation for color
-  // Maximum difference between colors (white - black) = 100%
-  Image_ColorXXX24 aDiff = {{255, 255, 255}};
-  const Standard_Integer aMaxDiffColor  = dotSquared (aDiff);
-  const Standard_Integer aDiffThreshold = Standard_Integer(Standard_Real(aMaxDiffColor) * myColorTolerance);
-
-  // we don't care about RGB/BGR/RGBA/BGRA/RGB32/BGR32 differences
-  // because we just compute summ of r g b components
-
-  // compare colors of each pixel
-  for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
+  switch (myImageRef->Format())
   {
-    for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
+    case Image_Format_Gray:
+    case Image_Format_Alpha:
     {
-      aDiff = myImageNew->Value<Image_ColorXXX24> (aRow, aCol) - myImageRef->Value<Image_ColorXXX24> (aRow, aCol);
-      if (dotSquared (aDiff) > aDiffThreshold)
+      // Tolerance of comparison operation for color
+      Standard_Integer aDiff = 255;
+      const Standard_Real    aMaxDiffColor  = aDiff * aDiff;
+      const Standard_Integer aDiffThreshold = Standard_Integer(aMaxDiffColor * myColorTolerance);
+      for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
       {
-        const Standard_Size aValue = pixel2Int (aRow, aCol);
-        myDiffPixels.Append (aValue);
-        ++aNbDiffColors;
+        for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
+        {
+          aDiff = Standard_Integer(myImageNew->Value<unsigned char> (aRow, aCol)) - Standard_Integer(myImageRef->Value<unsigned char> (aRow, aCol));
+          if (aDiff * aDiff > aDiffThreshold)
+          {
+            myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
+            ++aNbDiffColors;
+          }
+        }
       }
+      break;
+    }
+    case Image_Format_RGB:
+    case Image_Format_BGR:
+    case Image_Format_RGB32:
+    case Image_Format_BGR32:
+    case Image_Format_RGBA:
+    case Image_Format_BGRA:
+    {
+      // Tolerance of comparison operation for color
+      // Maximum difference between colors (white - black) = 100%
+      Image_ColorXXX24 aDiff = {{255, 255, 255}};
+      const Standard_Real    aMaxDiffColor  = dotSquared (aDiff);
+      const Standard_Integer aDiffThreshold = Standard_Integer(aMaxDiffColor * myColorTolerance);
+
+      // we don't care about RGB/BGR/RGBA/BGRA/RGB32/BGR32 differences
+      // because we just compute summ of r g b components
+      for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
+      {
+        for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
+        {
+          aDiff = myImageNew->Value<Image_ColorXXX24> (aRow, aCol) - myImageRef->Value<Image_ColorXXX24> (aRow, aCol);
+          if (dotSquared (aDiff) > aDiffThreshold)
+          {
+            myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
+            ++aNbDiffColors;
+          }
+        }
+      }
+      break;
+    }
+    default:
+    {
+      // Tolerance of comparison operation for color
+      // Maximum difference between colors (white - black) = 100%
+      NCollection_Vec3<float> aDiff (1.0f, 1.0f, 1.0f);
+      const Standard_Real    aMaxDiffColor  = aDiff.SquareModulus();
+      const Standard_Integer aDiffThreshold = Standard_Integer(aMaxDiffColor * myColorTolerance);
+      for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
+      {
+        for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
+        {
+          const Quantity_ColorRGBA aPixel1Rgba = myImageRef->PixelColor (Standard_Integer(aCol), Standard_Integer(aRow));
+          const Quantity_ColorRGBA aPixel2Rgba = myImageNew->PixelColor (Standard_Integer(aCol), Standard_Integer(aRow));
+          const NCollection_Vec3<float>& aPixel1 = aPixel1Rgba.GetRGB();
+          const NCollection_Vec3<float>& aPixel2 = aPixel2Rgba.GetRGB();
+          aDiff = aPixel2 - aPixel1;
+          if (aDiff.SquareModulus() > aDiffThreshold)
+          {
+            myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
+            ++aNbDiffColors;
+          }
+        }
+      }
+      break;
     }
   }
 
   // take into account a border effect
-  if (myIsBorderFilterOn && myDiffPixels.Length() > 0)
+  if (myIsBorderFilterOn && !myDiffPixels.IsEmpty())
   {
     aNbDiffColors = ignoreBorderEffect();
   }
@@ -341,17 +297,16 @@ Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const
 
   if (theDiffImage.IsEmpty()
    || theDiffImage.SizeX() != myImageRef->SizeX()
-   || theDiffImage.SizeY() != myImageRef->SizeY()
-   || !isSupportedFormat (theDiffImage.Format()))
+   || theDiffImage.SizeY() != myImageRef->SizeY())
   {
-    if (!theDiffImage.InitTrash (Image_Format_RGB, myImageRef->SizeX(), myImageRef->SizeY()))
+    if (!theDiffImage.InitTrash (Image_Format_Gray, myImageRef->SizeX(), myImageRef->SizeY()))
     {
       return Standard_False;
     }
   }
 
-  Standard_Size aRow, aCol;
-  const Image_ColorXXX24 aWhite = {{255, 255, 255}};
+  const Image_ColorXXX24   aWhite24 = {{255, 255, 255}};
+  const Quantity_ColorRGBA aWhiteRgba (1.0f, 1.0f, 1.0f, 1.0f);
 
   // initialize black image for dump
   memset (theDiffImage.ChangeData(), 0, theDiffImage.SizeBytes());
@@ -362,30 +317,86 @@ Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const
       return Standard_True;
     }
 
-    for (Standard_Integer aPixelId = 0; aPixelId < myDiffPixels.Length(); ++aPixelId)
+    switch (theDiffImage.Format())
     {
-      const Standard_Size aValue = myDiffPixels.Value (aPixelId);
-      int2Pixel (aValue, aRow, aCol);
-      theDiffImage.ChangeValue<Image_ColorXXX24> (aRow, aCol) = aWhite;
+      case Image_Format_Gray:
+      case Image_Format_Alpha:
+      {
+        for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter (myDiffPixels); aPixelIter.More(); aPixelIter.Next())
+        {
+          theDiffImage.ChangeValue<unsigned char> (UnpackY(aPixelIter.Value()), UnpackX(aPixelIter.Value())) = 255;
+        }
+        break;
+      }
+      case Image_Format_RGB:
+      case Image_Format_BGR:
+      case Image_Format_RGB32:
+      case Image_Format_BGR32:
+      case Image_Format_RGBA:
+      case Image_Format_BGRA:
+      {
+        for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter (myDiffPixels); aPixelIter.More(); aPixelIter.Next())
+        {
+          theDiffImage.ChangeValue<Image_ColorXXX24> (UnpackY(aPixelIter.Value()), UnpackX(aPixelIter.Value())) = aWhite24;
+        }
+        break;
+      }
+      default:
+      {
+        for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter (myDiffPixels); aPixelIter.More(); aPixelIter.Next())
+        {
+          theDiffImage.SetPixelColor (UnpackX(aPixelIter.Value()), UnpackY(aPixelIter.Value()), aWhiteRgba);
+        }
+        break;
+      }
     }
-
     return Standard_True;
   }
 
   Standard_Integer aGroupId = 1;
-  for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
+  for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
   {
     if (myLinearGroups.Contains (aGroupId))
     {
       continue; // skip linear groups
     }
 
-    const TColStd_MapOfInteger* aGroup = aGrIter.Value();
-    for (TColStd_MapIteratorOfMapOfInteger aPixelIter(*aGroup);
-         aPixelIter.More(); aPixelIter.Next())
+    const Handle(TColStd_HPackedMapOfInteger)& aGroup = aGrIter.Value();
+    switch (theDiffImage.Format())
     {
-      int2Pixel (aPixelIter.Key(), aRow, aCol);
-      theDiffImage.ChangeValue<Image_ColorXXX24> (aRow, aCol) = aWhite;
+      case Image_Format_Gray:
+      case Image_Format_Alpha:
+      {
+        for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
+        {
+          Standard_Integer aDiffPixel (aPixelIter.Key());
+          theDiffImage.ChangeValue<unsigned char> (UnpackY(aDiffPixel), UnpackX(aDiffPixel)) = 255;
+        }
+        break;
+      }
+      case Image_Format_RGB:
+      case Image_Format_BGR:
+      case Image_Format_RGB32:
+      case Image_Format_BGR32:
+      case Image_Format_RGBA:
+      case Image_Format_BGRA:
+      {
+        for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
+        {
+          Standard_Integer aDiffPixel (aPixelIter.Key());
+          theDiffImage.ChangeValue<Image_ColorXXX24> (UnpackY(aDiffPixel), UnpackX(aDiffPixel)) = aWhite24;
+        }
+        break;
+      }
+      default:
+      {
+        for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
+        {
+          Standard_Integer aDiffPixel (aPixelIter.Key());
+          theDiffImage.SetPixelColor (UnpackX(aDiffPixel), UnpackY(aDiffPixel), aWhiteRgba);
+        }
+        break;
+      }
     }
   }
 
@@ -404,7 +415,7 @@ Standard_Boolean Image_Diff::SaveDiffImage (const TCollection_AsciiString& theDi
   }
 
   Image_AlienPixMap aDiff;
-  if (!aDiff.InitTrash (Image_Format_RGB, myImageRef->SizeX(), myImageRef->SizeY())
+  if (!aDiff.InitTrash (Image_Format_Gray, myImageRef->SizeX(), myImageRef->SizeY())
    || !SaveDiffImage (aDiff))
   {
     return Standard_False;
@@ -430,39 +441,36 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
 
   // Find a different area (a set of close to each other pixels which colors differ in both images).
   // It filters alone pixels with different color.
-  Standard_Size aRow1 = 0, aCol1 = 0, aRow2, aCol2;
-  Standard_Integer aLen1 = (myDiffPixels.Length() > 0) ? (myDiffPixels.Length() - 1) : 0;
+  const Standard_Integer aLen1 = !myDiffPixels.IsEmpty() ? (myDiffPixels.Length() - 1) : 0;
   for (Standard_Integer aPixelId1 = 0; aPixelId1 < aLen1; ++aPixelId1)
   {
-    const Standard_Size aValue1 = myDiffPixels.Value (aPixelId1);
-    int2Pixel (aValue1, aRow1, aCol1);
+    Standard_Integer aValue1 = myDiffPixels.Value (aPixelId1);
 
     // Check other pixels in the list looking for a neighbour of this one
     for (Standard_Integer aPixelId2 = aPixelId1 + 1; aPixelId2 < myDiffPixels.Length(); ++aPixelId2)
     {
-      const Standard_Size aValue2 = myDiffPixels.Value (aPixelId2);
-      int2Pixel (aValue2, aRow2, aCol2);
-      if (getAbs (ptrdiff_t (aCol1 - aCol2)) <= 1 &&
-          getAbs (ptrdiff_t (aRow1 - aRow2)) <= 1)
+      Standard_Integer aValue2 = myDiffPixels.Value (aPixelId2);
+      if (Abs (Standard_Integer(UnpackX(aValue1)) - Standard_Integer(UnpackX(aValue2))) <= 1
+       && Abs (Standard_Integer(UnpackY(aValue1)) - Standard_Integer(UnpackY(aValue2))) <= 1)
       {
         // A neighbour is found. Create a new group and add both pixels.
         if (myGroupsOfDiffPixels.IsEmpty())
         {
-          TColStd_MapOfInteger* aGroup = new TColStd_MapOfInteger();
-          aGroup->Add ((Standard_Integer)aValue1);
-          aGroup->Add ((Standard_Integer)aValue2);
+          Handle(TColStd_HPackedMapOfInteger) aGroup = new TColStd_HPackedMapOfInteger();
+          aGroup->ChangeMap().Add (aValue1);
+          aGroup->ChangeMap().Add (aValue2);
           myGroupsOfDiffPixels.Append (aGroup);
         }
         else
         {
           // Find a group the pixels belong to.
           Standard_Boolean isFound = Standard_False;
-          for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next())
+          for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next())
           {
-            TColStd_MapOfInteger*& aGroup = aGrIter.ChangeValue();
-            if (aGroup->Contains ((Standard_Integer)aValue1))
+            const Handle(TColStd_HPackedMapOfInteger)& aGroup = aGrIter.ChangeValue();
+            if (aGroup->Map().Contains (aValue1))
             {
-              aGroup->Add ((Standard_Integer)aValue2);
+              aGroup->ChangeMap().Add (aValue2);
               isFound = Standard_True;
               break;
             }
@@ -471,9 +479,9 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
           if (!isFound)
           {
             // Create a new group
-            TColStd_MapOfInteger* aGroup = new TColStd_MapOfInteger();
-            aGroup->Add ((Standard_Integer)aValue1);
-            aGroup->Add ((Standard_Integer)aValue2);
+            Handle(TColStd_HPackedMapOfInteger) aGroup = new TColStd_HPackedMapOfInteger();
+            aGroup->ChangeMap().Add (aValue1);
+            aGroup->ChangeMap().Add (aValue2);
             myGroupsOfDiffPixels.Append (aGroup);
           }
         }
@@ -483,22 +491,31 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
 
   // filter linear groups which represent border of a solid shape
   Standard_Integer aGroupId = 1;
-  for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
+  for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
   {
     Standard_Integer aNeighboursNb = 0;
     Standard_Boolean isLine = Standard_True;
-    const TColStd_MapOfInteger* aGroup = aGrIter.Value();
-    for (TColStd_MapIteratorOfMapOfInteger aPixelIter (*aGroup); aPixelIter.More(); aPixelIter.Next())
+    const Handle(TColStd_HPackedMapOfInteger)& aGroup = aGrIter.Value();
+    if (aGroup->Map().IsEmpty())
     {
-      int2Pixel (aPixelIter.Key(), aRow1, aCol1);
+      continue;
+    }
+
+    Standard_Integer aDiffPixel = 0;
+    for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
+    {
+      aDiffPixel = aPixelIter.Key();
       aNeighboursNb = 0;
 
       // pixels of a line have only 1 or 2 neighbour pixels inside the same group
       // check all neighbour pixels on presence in the group
-      for (Standard_Size aNgbrIter = 0; aNgbrIter < NEIGHBOR_PIXELS_NB; ++aNgbrIter)
+      for (Standard_Size aNgbrIter = 0; aNgbrIter < Image_Diff_NbOfNeighborPixels; ++aNgbrIter)
       {
-        if (NEIGHBOR_PIXELS[aNgbrIter].isValid (*myImageRef, aRow1, aCol1)
-         && aGroup->Contains ((Standard_Integer)NEIGHBOR_PIXELS[aNgbrIter].pixel2Int (aRow1, aCol1)))
+        Standard_Integer anX = UnpackX(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][0];
+        Standard_Integer anY = UnpackY(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][1];
+        if (Standard_Size(anX) < myImageRef->SizeX()  // this unsigned math checks Standard_Size(-1) at-once
+         && Standard_Size(anY) < myImageRef->SizeY()
+         && aGroup->Map().Contains (PackXY((uint16_t)anX, (uint16_t)anY)))
         {
           ++aNeighboursNb;
         }
@@ -509,7 +526,7 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
         isLine = Standard_False;
         break;
       }
-    } // for pixels inside group...
+    }
 
     if (isLine)
     {
@@ -518,10 +535,13 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
       // If the pixel has greater than 1 not black neighbour pixel, it is a border of a shape.
       // Otherwise, it may be a topological edge, for example.
       aNeighboursNb = 0;
-      for (Standard_Size aNgbrIter = 0; aNgbrIter < NEIGHBOR_PIXELS_NB; ++aNgbrIter)
+      for (Standard_Size aNgbrIter = 0; aNgbrIter < Image_Diff_NbOfNeighborPixels; ++aNgbrIter)
       {
-        if ( NEIGHBOR_PIXELS[aNgbrIter].isValid (*myImageRef, aRow1, aCol1)
-         && !NEIGHBOR_PIXELS[aNgbrIter].isBlack (*myImageRef, aRow1, aCol1))
+        Standard_Integer anX = UnpackX(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][0];
+        Standard_Integer anY = UnpackY(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][1];
+        if (Standard_Size(anX) < myImageRef->SizeX()  // this unsigned math checks Standard_Size(-1) at-once
+        &&  Standard_Size(anY) < myImageRef->SizeY()
+        && !isBlackPixel (*myImageRef, Standard_Size(anY), Standard_Size(anX)))
         {
           ++aNeighboursNb;
         }
@@ -532,15 +552,17 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
         myLinearGroups.Add (aGroupId);
       }
     }
-  } // for groups...
+  }
 
   // number of different groups of pixels (except linear groups)
   Standard_Integer aNbDiffColors = 0;
   aGroupId = 1;
-  for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
+  for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
   {
     if (!myLinearGroups.Contains (aGroupId))
+    {
       ++aNbDiffColors;
+    }
   }
 
   return aNbDiffColors;
@@ -552,11 +574,6 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
 // =======================================================================
 void Image_Diff::releaseGroupsOfDiffPixels()
 {
-  for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next())
-  {
-    TColStd_MapOfInteger*& aGroup = aGrIter.ChangeValue();
-    delete aGroup;
-  }
   myGroupsOfDiffPixels.Clear();
   myLinearGroups.Clear();
 }
index 548c6ba..79f2046 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <Image_PixMap.hxx>
 #include <TCollection_AsciiString.hxx>
-#include <TColStd_MapOfInteger.hxx>
+#include <TColStd_HPackedMapOfInteger.hxx>
 #include <NCollection_List.hxx>
 #include <NCollection_Vector.hxx>
 
@@ -81,10 +81,10 @@ public:
   //! Color tolerance for equality check. Should be within range 0..1:
   //! Corresponds to a difference between white and black colors (maximum difference).
   //! By default, the tolerance is equal to 0 thus equality check will return false for any different colors.
-  Standard_EXPORT void SetColorTolerance (const Standard_Real theTolerance);
+  void SetColorTolerance (const Standard_Real theTolerance) {  myColorTolerance = theTolerance; }
 
   //! Color tolerance for equality check.
-  Standard_EXPORT Standard_Real ColorTolerance() const;
+  Standard_Real ColorTolerance() const { return myColorTolerance; }
 
   //! Sets taking into account (ignoring) a "border effect" on comparison of images.
   //! The border effect is caused by a border of shaded shapes in the viewer 3d.
@@ -92,10 +92,10 @@ public:
   //! Therefore, they deflect light differently according to implementation of a video card driver.
   //! This flag allows to detect such a "border" area and skip it from comparison of images.
   //! Filter turned OFF by default.
-  Standard_EXPORT void SetBorderFilterOn (const Standard_Boolean theToIgnore);
+  void SetBorderFilterOn (const Standard_Boolean theToIgnore) { myIsBorderFilterOn = theToIgnore; }
 
   //! Returns a flag of taking into account (ignoring) a border effect in comparison of images.
-  Standard_EXPORT Standard_Boolean IsBorderFilterOn() const;
+  Standard_Boolean IsBorderFilterOn() const { return myIsBorderFilterOn; }
 
   //! Compares two images. It returns a number of different pixels (or groups of pixels).
   //! It returns -1 if algorithm not initialized before.
@@ -117,15 +117,38 @@ protected:
 
 protected:
 
-  typedef NCollection_List<TColStd_MapOfInteger* > ListOfMapOfInteger;
+  //! Map two pixel coordinates to 32-bit integer
+  static Standard_Integer PackXY (uint16_t theX, uint16_t theY)
+  {
+    return Standard_Integer((unsigned int)theY | 
+                           ((unsigned int)theX << 16));
+  }
+
+  //! Get pixel X coordinate from 32-bit packed integer
+  static uint16_t UnpackX (Standard_Integer theXY)
+  {
+    return (uint16_t)(((unsigned int)theXY & 0xffff0000) >> 16);
+  }
+
+  //! Get pixel Y coordinate from 32-bit packed integer
+  static uint16_t UnpackY (Standard_Integer theXY)
+  {
+    return (uint16_t)((unsigned int)theXY & 0xffff);
+  }
+
+protected:
 
   Handle(Image_PixMap)              myImageRef;           //!< reference image to compare (from)
   Handle(Image_PixMap)              myImageNew;           //!< new       image to compare (to)
   Standard_Real                     myColorTolerance;     //!< tolerance for equality check (0..1, 0 - any not equal, 1 - opposite colors)
+
   Standard_Boolean                  myIsBorderFilterOn;   //!< perform algorithm with border effect filter
-  ListOfMapOfInteger                myGroupsOfDiffPixels;
-  NCollection_Vector<Standard_Size> myDiffPixels;         //!< different pixels (position packed into integer)
-  TColStd_MapOfInteger              myLinearGroups;
+
+  //! coordinates of different pixels, packed in one int using 16-bit integers to save memory
+  NCollection_Vector<Standard_Integer> myDiffPixels;
+  TColStd_PackedMapOfInteger        myLinearGroups;
+  NCollection_List<Handle(TColStd_HPackedMapOfInteger)>
+                                    myGroupsOfDiffPixels;
 
 public:
 
index 7538d36..638324d 100644 (file)
@@ -191,16 +191,14 @@ void Image_PixMap::Clear()
 // function : PixelColor
 // purpose  :
 // =======================================================================
-Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
-                                         const Standard_Integer theY,
-                                         Standard_Real& theAlpha) const
+Quantity_ColorRGBA Image_PixMap::PixelColor (const Standard_Integer theX,
+                                             const Standard_Integer theY) const
 {
   if (IsEmpty()
    || theX < 0 || (Standard_Size )theX >= SizeX()
    || theY < 0 || (Standard_Size )theY >= SizeY())
   {
-    theAlpha = 0.0; // transparent
-    return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
+    return Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 0.0f); // transparent
   }
 
   switch (myImgFormat)
@@ -208,86 +206,72 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
     case Image_Format_GrayF:
     {
       const Standard_ShortReal& aPixel = Value<Standard_ShortReal> (theY, theX);
-      theAlpha = 1.0; // opaque
-      return Quantity_Color (aPixel, aPixel, aPixel, Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel, aPixel, aPixel, 1.0f)); // opaque
     }
     case Image_Format_AlphaF:
     {
       const Standard_ShortReal& aPixel = Value<Standard_ShortReal> (theY, theX);
-      theAlpha = aPixel;
-      return Quantity_Color (1.0, 1.0, 1.0, Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (NCollection_Vec4<float> (1.0f, 1.0f, 1.0f, aPixel));
     }
     case Image_Format_RGBAF:
     {
       const Image_ColorRGBAF& aPixel = Value<Image_ColorRGBAF> (theY, theX);
-      theAlpha = aPixel.a();
-      return Quantity_Color (aPixel.r(), aPixel.g(), aPixel.b(), Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), aPixel.a()));
     }
     case Image_Format_BGRAF:
     {    
       const Image_ColorBGRAF& aPixel = Value<Image_ColorBGRAF> (theY, theX);
-      theAlpha = aPixel.a();
-      return Quantity_Color (aPixel.r(), aPixel.g(), aPixel.b(), Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), aPixel.a()));
     }
     case Image_Format_RGBF:
     {
       const Image_ColorRGBF& aPixel = Value<Image_ColorRGBF> (theY, theX);
-      theAlpha =  1.0; // opaque
-      return Quantity_Color (aPixel.r(), aPixel.g(), aPixel.b(), Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), 1.0f)); // opaque
     }
     case Image_Format_BGRF:
     {
       const Image_ColorBGRF& aPixel = Value<Image_ColorBGRF> (theY, theX);
-      theAlpha =  1.0; // opaque
-      return Quantity_Color (aPixel.r(), aPixel.g(), aPixel.b(), Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), 1.0f)); // opaque
     }
     case Image_Format_RGBA:
     {
       const Image_ColorRGBA& aPixel = Value<Image_ColorRGBA> (theY, theX);
-      theAlpha = Standard_Real (aPixel.a()) / 255.0;
-      return Quantity_Color (Standard_Real (aPixel.r()) / 255.0, Standard_Real (aPixel.g()) / 255.0, Standard_Real (aPixel.b()) / 255.0, Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, float(aPixel.a()) / 255.0f);
     }
     case Image_Format_BGRA:
     {
       const Image_ColorBGRA& aPixel = Value<Image_ColorBGRA> (theY, theX);
-      theAlpha = Standard_Real (aPixel.a()) / 255.0;
-      return Quantity_Color (Standard_Real (aPixel.r()) / 255.0, Standard_Real (aPixel.g()) / 255.0, Standard_Real (aPixel.b() / 255.0), Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, float(aPixel.a()) / 255.0f);
     }
     case Image_Format_RGB32:
     {
       const Image_ColorRGB32& aPixel = Value<Image_ColorRGB32> (theY, theX);
-      theAlpha = 1.0; // opaque
-      return Quantity_Color (Standard_Real (aPixel.r()) / 255.0, Standard_Real (aPixel.g()) / 255.0, Standard_Real (aPixel.b()) / 255.0, Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
     }
     case Image_Format_BGR32:
     {
       const Image_ColorBGR32& aPixel = Value<Image_ColorBGR32> (theY, theX);
-      theAlpha = 1.0; // opaque
-      return Quantity_Color (Standard_Real (aPixel.r()) / 255.0, Standard_Real (aPixel.g()) / 255.0, Standard_Real (aPixel.b()) / 255.0, Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
     }
     case Image_Format_RGB:
     {
       const Image_ColorRGB& aPixel = Value<Image_ColorRGB> (theY, theX);
-      theAlpha = 1.0; // opaque
-      return Quantity_Color (Standard_Real (aPixel.r()) / 255.0, Standard_Real (aPixel.g()) / 255.0, Standard_Real (aPixel.b()) / 255.0, Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
     }
     case Image_Format_BGR:
     {
       const Image_ColorBGR& aPixel = Value<Image_ColorBGR> (theY, theX);
-      theAlpha = 1.0; // opaque
-      return Quantity_Color (Standard_Real (aPixel.r()) / 255.0, Standard_Real (aPixel.g()) / 255.0, Standard_Real (aPixel.b()) / 255.0, Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
     }
     case Image_Format_Gray:
     {
       const Standard_Byte& aPixel = Value<Standard_Byte> (theY, theX);
-      theAlpha = 1.0; // opaque
-      return Quantity_Color (Standard_Real (aPixel) / 255.0, Standard_Real (aPixel) / 255.0, Standard_Real (aPixel) / 255.0, Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (float(aPixel) / 255.0f, float(aPixel) / 255.0f, float(aPixel) / 255.0f, 1.0f); // opaque
     }
     case Image_Format_Alpha:
     {
       const Standard_Byte& aPixel = Value<Standard_Byte> (theY, theX);
-      theAlpha = Standard_Real (aPixel) / 255.0;
-      return Quantity_Color (1.0, 1.0, 1.0, Quantity_TOC_RGB);
+      return Quantity_ColorRGBA (1.0f, 1.0f, 1.0f, float(aPixel) / 255.0f);
     }
     case Image_Format_UNKNOWN:
     {
@@ -296,8 +280,7 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
   }
 
   // unsupported image type
-  theAlpha = 0.0; // transparent
-  return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
+  return Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 0.0f); // transparent
 }
 
 // =======================================================================
@@ -306,7 +289,7 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
 // =======================================================================
 void Image_PixMap::SetPixelColor (const Standard_Integer theX,
                                   const Standard_Integer theY,
-                                  const NCollection_Vec4<float>& theColor)
+                                  const Quantity_ColorRGBA& theColor)
 {
   if (IsEmpty()
    || theX < 0 || Standard_Size(theX) >= SizeX()
@@ -315,112 +298,113 @@ void Image_PixMap::SetPixelColor (const Standard_Integer theX,
     return;
   }
 
+  const NCollection_Vec4<float>& aColor = theColor;
   switch (myImgFormat)
   {
     case Image_Format_GrayF:
     {
-      ChangeValue<Standard_ShortReal> (theY, theX) = theColor.r();
+      ChangeValue<Standard_ShortReal> (theY, theX) = aColor.r();
       return;
     }
     case Image_Format_AlphaF:
     {
-      ChangeValue<Standard_ShortReal> (theY, theX) = theColor.a();
+      ChangeValue<Standard_ShortReal> (theY, theX) = aColor.a();
       return;
     }
     case Image_Format_RGBAF:
     {
       Image_ColorRGBAF& aPixel = ChangeValue<Image_ColorRGBAF> (theY, theX);
-      aPixel.r() = theColor.r();
-      aPixel.g() = theColor.g();
-      aPixel.b() = theColor.b();
-      aPixel.a() = theColor.a();
+      aPixel.r() = aColor.r();
+      aPixel.g() = aColor.g();
+      aPixel.b() = aColor.b();
+      aPixel.a() = aColor.a();
       return;
     }
     case Image_Format_BGRAF:
     {
       Image_ColorBGRAF& aPixel = ChangeValue<Image_ColorBGRAF> (theY, theX);
-      aPixel.r() = theColor.r();
-      aPixel.g() = theColor.g();
-      aPixel.b() = theColor.b();
-      aPixel.a() = theColor.a();
+      aPixel.r() = aColor.r();
+      aPixel.g() = aColor.g();
+      aPixel.b() = aColor.b();
+      aPixel.a() = aColor.a();
       return;
     }
     case Image_Format_RGBF:
     {
       Image_ColorRGBF& aPixel = ChangeValue<Image_ColorRGBF> (theY, theX);
-      aPixel.r() = theColor.r();
-      aPixel.g() = theColor.g();
-      aPixel.b() = theColor.b();
+      aPixel.r() = aColor.r();
+      aPixel.g() = aColor.g();
+      aPixel.b() = aColor.b();
       return;
     }
     case Image_Format_BGRF:
     {
       Image_ColorBGRF& aPixel = ChangeValue<Image_ColorBGRF> (theY, theX);
-      aPixel.r() = theColor.r();
-      aPixel.g() = theColor.g();
-      aPixel.b() = theColor.b();
+      aPixel.r() = aColor.r();
+      aPixel.g() = aColor.g();
+      aPixel.b() = aColor.b();
       return;
     }
     case Image_Format_RGBA:
     {
       Image_ColorRGBA& aPixel = ChangeValue<Image_ColorRGBA> (theY, theX);
-      aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
-      aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
-      aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
-      aPixel.a() = Standard_Byte(theColor.a() * 255.0f);
+      aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
+      aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
+      aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
+      aPixel.a() = Standard_Byte(aColor.a() * 255.0f);
       return;
     }
     case Image_Format_BGRA:
     {
       Image_ColorBGRA& aPixel = ChangeValue<Image_ColorBGRA> (theY, theX);
-      aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
-      aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
-      aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
-      aPixel.a() = Standard_Byte(theColor.a() * 255.0f);
+      aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
+      aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
+      aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
+      aPixel.a() = Standard_Byte(aColor.a() * 255.0f);
       return;
     }
     case Image_Format_RGB32:
     {
       Image_ColorRGB32& aPixel = ChangeValue<Image_ColorRGB32> (theY, theX);
-      aPixel.r()  = Standard_Byte(theColor.r() * 255.0f);
-      aPixel.g()  = Standard_Byte(theColor.g() * 255.0f);
-      aPixel.b()  = Standard_Byte(theColor.b() * 255.0f);
+      aPixel.r()  = Standard_Byte(aColor.r() * 255.0f);
+      aPixel.g()  = Standard_Byte(aColor.g() * 255.0f);
+      aPixel.b()  = Standard_Byte(aColor.b() * 255.0f);
       aPixel.a_() = 255;
       return;
     }
     case Image_Format_BGR32:
     {
       Image_ColorBGR32& aPixel = ChangeValue<Image_ColorBGR32> (theY, theX);
-      aPixel.r()  = Standard_Byte(theColor.r() * 255.0f);
-      aPixel.g()  = Standard_Byte(theColor.g() * 255.0f);
-      aPixel.b()  = Standard_Byte(theColor.b() * 255.0f);
+      aPixel.r()  = Standard_Byte(aColor.r() * 255.0f);
+      aPixel.g()  = Standard_Byte(aColor.g() * 255.0f);
+      aPixel.b()  = Standard_Byte(aColor.b() * 255.0f);
       aPixel.a_() = 255;
       return;
     }
     case Image_Format_RGB:
     {
       Image_ColorRGB& aPixel = ChangeValue<Image_ColorRGB> (theY, theX);
-      aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
-      aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
-      aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
+      aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
+      aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
+      aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
       return;
     }
     case Image_Format_BGR:
     {
       Image_ColorBGR& aPixel = ChangeValue<Image_ColorBGR> (theY, theX);
-      aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
-      aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
-      aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
+      aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
+      aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
+      aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
       return;
     }
     case Image_Format_Gray:
     {
-      ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(theColor.r() * 255.0f);
+      ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(aColor.r() * 255.0f);
       return;
     }
     case Image_Format_Alpha:
     {
-      ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(theColor.a() * 255.0f);
+      ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(aColor.a() * 255.0f);
       return;
     }
     case Image_Format_UNKNOWN:
@@ -499,3 +483,72 @@ bool Image_PixMap::SwapRgbaBgra (Image_PixMap& theImage)
     default: return false;
   }
 }
+
+// =======================================================================
+// function : ToBlackWhite
+// purpose  :
+// =======================================================================
+void Image_PixMap::ToBlackWhite (Image_PixMap& theImage)
+{
+  switch (theImage.Format())
+  {
+    case Image_Format_Gray:
+    case Image_Format_Alpha:
+    {
+      for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
+      {
+        for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
+        {
+          unsigned char& aPixel = theImage.ChangeValue<unsigned char> (aRow, aCol);
+          if (aPixel != 0)
+          {
+            aPixel = 255;
+          }
+        }
+      }
+      break;
+    }
+    case Image_Format_RGB:
+    case Image_Format_BGR:
+    case Image_Format_RGB32:
+    case Image_Format_BGR32:
+    case Image_Format_RGBA:
+    case Image_Format_BGRA:
+    {
+      const NCollection_Vec3<unsigned char> aWhite24 (255, 255, 255);
+      for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
+      {
+        for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
+        {
+          NCollection_Vec3<unsigned char>& aPixel = theImage.ChangeValue< NCollection_Vec3<unsigned char> > (aRow, aCol);
+          if (aPixel[0] != 0
+           || aPixel[1] != 0
+           || aPixel[2] != 0)
+          {
+            aPixel = aWhite24;
+          }
+        }
+      }
+      break;
+    }
+    default:
+    {
+      const Quantity_ColorRGBA aWhiteRgba (1.0f, 1.0f, 1.0f, 1.0f);
+      for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
+      {
+        for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
+        {
+          const Quantity_ColorRGBA       aPixelRgba = theImage.PixelColor (Standard_Integer(aCol), Standard_Integer(aRow));
+          const NCollection_Vec4<float>& aPixel     = aPixelRgba;
+          if (aPixel[0] != 0.0f
+           || aPixel[1] != 0.0f
+           || aPixel[2] != 0.0f)
+          {
+            theImage.SetPixelColor (int(aCol), int(aRow), aWhiteRgba);
+          }
+        }
+      }
+      break;
+    }
+  }
+}
index 39f3630..7394af9 100644 (file)
@@ -45,6 +45,9 @@ public:
   //!  - Image_Format_RGBAF / Image_Format_BGRAF
   Standard_EXPORT static bool SwapRgbaBgra (Image_PixMap& theImage);
 
+  //! Convert image to Black/White.
+  Standard_EXPORT static void ToBlackWhite (Image_PixMap& theImage);
+
 public: // high-level API
 
   Image_Format Format() const { return myImgFormat; }
@@ -102,45 +105,23 @@ public: // high-level API
   //! @param theX column index from left
   //! @param theY row    index from top
   //! @return the pixel color
-  inline Quantity_Color PixelColor (const Standard_Integer theX,
-                                    const Standard_Integer theY) const
-  {
-    Standard_Real aDummy;
-    return PixelColor (theX, theY, aDummy);
-  }
-
-  //! Returns the pixel color. This function is relatively slow.
-  //! theAlpha argument is set to color intensity (0 - transparent, 1 - opaque)
-  //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
-  Standard_EXPORT Quantity_Color PixelColor (const Standard_Integer theX,
-                                             const Standard_Integer theY,
-                                             Standard_Real& theAlpha) const;
-
-  //! Sets the pixel color. This function is relatively slow.
-  //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
-  void SetPixelColor (const Standard_Integer    theX,
-                      const Standard_Integer    theY,
-                      const Quantity_ColorRGBA& theColor)
-  {
-    const NCollection_Vec4<float> aColor = theColor;
-    SetPixelColor (theX, theY, aColor);
-  }
+  Standard_EXPORT Quantity_ColorRGBA PixelColor (const Standard_Integer theX,
+                                                 const Standard_Integer theY) const;
 
   //! Sets the pixel color. This function is relatively slow.
   //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
-  void SetPixelColor(const Standard_Integer theX,
-                     const Standard_Integer theY,
-                     const Quantity_Color&  theColor)
+  void SetPixelColor (const Standard_Integer theX,
+                      const Standard_Integer theY,
+                      const Quantity_Color&  theColor)
   {
-    const NCollection_Vec3<float> aColor = theColor;
-    SetPixelColor (theX, theY, NCollection_Vec4<float> (aColor, 1.0f));
+    SetPixelColor (theX, theY, Quantity_ColorRGBA (theColor, 1.0f));
   }
 
   //! Sets the pixel color. This function is relatively slow.
   //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
   Standard_EXPORT void SetPixelColor (const Standard_Integer theX,
                                       const Standard_Integer theY,
-                                      const NCollection_Vec4<float>& theColor);
+                                      const Quantity_ColorRGBA& theColor);
 
   //! Initialize image plane as wrapper over alien data.
   //! Data will not be copied! Notice that caller should ensure
index 132b6db..bb74d07 100644 (file)
@@ -57,6 +57,14 @@ public:
     v[1] = theY;
   }
 
+  //! Assign new values to the vector.
+  void SetValues (const Element_t theX,
+                  const Element_t theY)
+  {
+    v[0] = theX;
+    v[1] = theY;
+  }
+
   //! Alias to 1st component as X coordinate in XY.
   Element_t x() const { return v[0]; }
 
index 91e2468..ed6cf98 100644 (file)
@@ -73,6 +73,16 @@ public:
     v[2] = Element_t(0);
   }
 
+  //! Assign new values to the vector.
+  void SetValues (const Element_t theX,
+                  const Element_t theY,
+                  const Element_t theZ)
+  {
+    v[0] = theX;
+    v[1] = theY;
+    v[2] = theZ;
+  }
+
   //! Alias to 1st component as X coordinate in XYZ.
   Element_t x() const { return v[0]; }
 
index 9bc63f9..0870412 100644 (file)
@@ -80,6 +80,18 @@ public:
     v[3] = theAlpha;
   }
 
+  //! Assign new values to the vector.
+  void SetValues (const Element_t theX,
+                  const Element_t theY,
+                  const Element_t theZ,
+                  const Element_t theW)
+  {
+    v[0] = theX;
+    v[1] = theY;
+    v[2] = theZ;
+    v[3] = theW;
+  }
+
   //! Alias to 1st component as X coordinate in XYZW.
   Element_t x() const { return v[0]; }
 
index 5e5f9da..8f91d9f 100644 (file)
@@ -26,10 +26,32 @@ public:
   Quantity_ColorRGBA() : myAlpha (1.0f) {}
 
   //! Creates the color with specified RGB value.
-  explicit Quantity_ColorRGBA (const Quantity_Color& theRgb) : myRgb (theRgb), myAlpha (1.0f) {}
+  explicit Quantity_ColorRGBA (const Quantity_Color& theRgb)
+  : myRgb (theRgb), myAlpha (1.0f)
+  {}
+
+  //! Creates the color with specified RGBA values.
+  Quantity_ColorRGBA (const Quantity_Color& theRgb, float theAlpha)
+  : myRgb (theRgb), myAlpha (theAlpha)
+  {}
 
   //! Creates the color from RGBA vector.
-  explicit Quantity_ColorRGBA (const NCollection_Vec4<float>& theRgba) : myRgb (theRgba.rgb()), myAlpha (theRgba.a()) {}
+  explicit Quantity_ColorRGBA (const NCollection_Vec4<float>& theRgba) 
+  : myRgb (theRgba.rgb()), myAlpha (theRgba.a())
+  {}
+
+  //! Creates the color from RGBA values.
+  Quantity_ColorRGBA (float theRed, float theGreen, float theBlue, float theAlpha)
+  : myRgb (theRed, theGreen, theBlue, Quantity_TOC_RGB),
+    myAlpha (theAlpha)
+  {}
+
+  //! Assign new values to the color.
+  void SetValues (float theRed, float theGreen, float theBlue, float theAlpha)
+  {
+    myRgb.SetValues (theRed, theGreen, theBlue, Quantity_TOC_RGB);
+    myAlpha = theAlpha;
+  }
 
   //! Return RGB color value.
   const Quantity_Color& GetRGB() const { return myRgb; }
@@ -71,8 +93,8 @@ public:
 
 private:
 
-  static void __testSize3() { Standard_STATIC_ASSERT (sizeof(float) * 3 == sizeof(Quantity_Color)); }
-  static void __testSize4() { Standard_STATIC_ASSERT (sizeof(float) * 4 == sizeof(Quantity_ColorRGBA)); }
+  static void myTestSize3() { Standard_STATIC_ASSERT (sizeof(float) * 3 == sizeof(Quantity_Color)); }
+  static void myTestSize4() { Standard_STATIC_ASSERT (sizeof(float) * 4 == sizeof(Quantity_ColorRGBA)); }
 
 private:
 
index 8e259be..e666353 100644 (file)
@@ -840,7 +840,7 @@ namespace
            || aDepth >=  ShortRealLast())
           {
             myImage->SetPixelColor (Standard_Integer(aColIter), Standard_Integer(aRowIter),
-                                    NCollection_Vec4<float> (0.0f, 0.0f, 0.0f, 1.0f));
+                                    Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 1.0f));
             continue;
           }
 
@@ -850,7 +850,7 @@ namespace
             aNormDepth = 1.0f - aNormDepth;
           }
           myImage->SetPixelColor (Standard_Integer(aColIter), Standard_Integer(aRowIter),
-                                  NCollection_Vec4<float> (aNormDepth, aNormDepth, aNormDepth, 1.0f));
+                                  Quantity_ColorRGBA (aNormDepth, aNormDepth, aNormDepth, 1.0f));
         }
       }
     }
@@ -878,13 +878,13 @@ namespace
       if (thePicked < 1
        || thePicked > myMainSel->NbPicked())
       {
-        myImage->SetPixelColor (theCol, theRow, NCollection_Vec4<float> (0.0f, 0.0f, 0.0f, 1.0f));
+        myImage->SetPixelColor (theCol, theRow, Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 1.0f));
         return;
       }
 
       const SelectMgr_SortCriterion& aSortCriterion = myMainSel->PickedData (thePicked);
       const float aDepth = float(aSortCriterion.Depth);
-      myImage->SetPixelColor (theCol, theRow, NCollection_Vec4<float> (aDepth, aDepth, aDepth, 1.0f));
+      myImage->SetPixelColor (theCol, theRow, Quantity_ColorRGBA (aDepth, aDepth, aDepth, 1.0f));
     }
   };
 
index 6ac6cc6..cb2ce78 100644 (file)
@@ -5848,17 +5848,16 @@ static int VReadPixel (Draw_Interpretor& theDI,
     return 1;
   }
 
-  Standard_Real anAlpha;
-  Quantity_Color aColor = anImage.PixelColor (anX, anY, anAlpha);
+  Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY);
   if (toShowName)
   {
     if (aBufferType == Graphic3d_BT_RGBA)
     {
-      theDI << Quantity_Color::StringName (aColor.Name()) << " " << anAlpha;
+      theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
     }
     else
     {
-      theDI << Quantity_Color::StringName (aColor.Name());
+      theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
     }
   }
   else
@@ -5870,22 +5869,22 @@ static int VReadPixel (Draw_Interpretor& theDI,
       {
         if (toShowHls)
         {
-          theDI << aColor.Hue() << " " << aColor.Light() << " " << aColor.Saturation();
+          theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
         }
         else
         {
-          theDI << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue();
+          theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
         }
         break;
       }
       case Graphic3d_BT_RGBA:
       {
-        theDI << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue() << " " << anAlpha;
+        theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue() << " " << aColor.Alpha();
         break;
       }
       case Graphic3d_BT_Depth:
       {
-        theDI << aColor.Red();
+        theDI << aColor.GetRGB().Red();
         break;
       }
     }