0023156: Image_PixMap::PixelColor() extended to return alpha value
authorvro <vro@opencascade.com>
Fri, 22 Jun 2012 07:29:55 +0000 (11:29 +0400)
committersan <san@opencascade.com>
Mon, 25 Jun 2012 07:16:14 +0000 (11:16 +0400)
Implemented new method to provide access to alpha value in image.

Implemented new vreadpixel Draw Harness command to read
specified pixel value from 3D view.
vdump command - added result checks
Corrected misprint

src/Image/Image_PixMap.cdl
src/Image/Image_PixMap.cxx
src/V3d/V3d_View.cxx
src/ViewerTest/ViewerTest.cxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx

index 8bf6ffc..ad528f3 100644 (file)
@@ -34,7 +34,8 @@ uses
     TypeOfImage    from Image,
     HPrivateImage  from Image,
     CRawBufferData from Image,
-    Color          from Quantity
+    Color          from Quantity,
+    Parameter      from Quantity
 
 raises
     PixmapDefinitionError  from Aspect,
@@ -128,6 +129,19 @@ is
     -- Note that this function convert input theY coordinate
     -- to count off from top of an image (while in memory it stored
     -- upside-down).
+
+    PixelColor ( me         : in;
+                 theX, theY : in  Integer   from Standard;
+                 theAlpha   : out Parameter from Quantity )
+    returns Color from Quantity;
+    ---Purpose:
+    -- Returns the pixel color. This function is relatively slow,
+    -- use AccessBuffer() instead for stream operations.
+    -- theAlpha argument is set to color intensity (0 - transparent, 1 - opaque)
+    -- Note that this function convert input theY coordinate
+    -- to count off from top of an image (while in memory it stored
+    -- upside-down).
+
 fields
     myImage : HPrivateImage from Image is protected;
 end PixMap;
index a0927fd..3065861 100644 (file)
     }
 
     Quantity_Color getPixelColor (const Standard_Integer theCol,
-                                  const Standard_Integer theRow) const
+                                  const Standard_Integer theRow,
+                                  Quantity_Parameter&    theAlpha) const
     {
       RGBQuad_t* aPixel = (RGBQuad_t* )&getScanLine (theRow)[theCol * myBytesPerPixel];
+      theAlpha = (myBytesPerPixel > 3) ? (Standard_Real (aPixel->rgbReserved) / 255.0) : 1.0;
       return Quantity_Color (Standard_Real (aPixel->rgbRed)   / 255.0,
                              Standard_Real (aPixel->rgbGreen) / 255.0,
                              Standard_Real (aPixel->rgbBlue)  / 255.0,
@@ -414,13 +416,30 @@ void Image_PixMap::AccessBuffer (Image_CRawBufferData& theBuffer) const
 #endif
 }
 
+// =======================================================================
+// function : PixelColor
+// purpose  :
+// =======================================================================
 Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
                                          const Standard_Integer theY) const
 {
+  Quantity_Parameter aDummy;
+  return PixelColor (theX, theY, aDummy);
+}
+
+// =======================================================================
+// function : PixelColor
+// purpose  :
+// =======================================================================
+Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
+                                         const Standard_Integer theY,
+                                         Quantity_Parameter&    theAlpha) const
+{
   Standard_Integer aScanlineId = myImage->getHeight() - theY - 1;
-  if (theX < 0 || theX >= (unsigned int)myImage->getWidth() ||
-      theY < 0 || theY >= (unsigned int)myImage->getHeight())
+  if (theX < 0 || (unsigned int )theX >= (unsigned int )myImage->getWidth() ||
+      theY < 0 || (unsigned int )theY >= (unsigned int )myImage->getHeight())
   {
+    theAlpha = 0.0; // transparent
     return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
   }
 #ifdef HAVE_FREEIMAGE
@@ -428,6 +447,7 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
   {
     RGBQUAD aValue; memset (&aValue, 0, sizeof(aValue));
     myImage->getPixelColor (theX, aScanlineId, &aValue);
+    theAlpha = (myImage->getColorType() == FIC_RGBALPHA) ? (Standard_Real (aValue.rgbReserved) / 255.0) : 1.0;
     return Quantity_Color (Standard_Real (aValue.rgbRed)   / 255.0,
                            Standard_Real (aValue.rgbGreen) / 255.0,
                            Standard_Real (aValue.rgbBlue)  / 255.0,
@@ -441,12 +461,14 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
       {
         float* aScanLine = (float* )myImage->getScanLine (aScanlineId);
         Quantity_Parameter aValue = Quantity_Parameter (aScanLine[theX]);
+        theAlpha = 1.0; // opaque
         return Quantity_Color (aValue, aValue, aValue, Quantity_TOC_RGB);
       }
       case FIT_RGBF:
       {
         FIRGBF* aScanLine = (FIRGBF* )myImage->getScanLine (aScanlineId);
         FIRGBF* aPixel = &aScanLine[theX];
+        theAlpha = 1.0; // opaque
         return Quantity_Color (Quantity_Parameter (aPixel->red),
                                Quantity_Parameter (aPixel->green),
                                Quantity_Parameter (aPixel->blue),
@@ -456,6 +478,7 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
       {
         FIRGBAF* aScanLine = (FIRGBAF* )myImage->getScanLine (aScanlineId);
         FIRGBAF* aPixel = &aScanLine[theX];
+        theAlpha = aPixel->alpha;
         return Quantity_Color (Quantity_Parameter (aPixel->red),
                                Quantity_Parameter (aPixel->green),
                                Quantity_Parameter (aPixel->blue),
@@ -464,11 +487,12 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
       default:
       {
         // not supported image type
+        theAlpha = 0.0; // transparent
         return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
       }
     }
   }
 #else
-  return myImage->getPixelColor (theX, aScanlineId);
+  return myImage->getPixelColor (theX, aScanlineId, theAlpha);
 #endif
 }
index 4dc97ec..04df995 100755 (executable)
@@ -3534,15 +3534,16 @@ Handle(Image_PixMap) V3d_View::ToPixMap (const Standard_Integer  theWidth,
   Graphic3d_CView* cView = (Graphic3d_CView* )MyView->CView();
   Graphic3d_PtrFrameBuffer aFBOPtr = NULL;
   Graphic3d_PtrFrameBuffer aPrevFBOPtr = (Graphic3d_PtrFrameBuffer )cView->ptrFBO;
+  Standard_Integer aFBOVPSizeX (theWidth), aFBOVPSizeY (theHeight), aFBOSizeXMax (0), aFBOSizeYMax (0);
   Standard_Integer aPrevFBOVPSizeX (0), aPrevFBOVPSizeY (0), aPrevFBOSizeXMax (0), aPrevFBOSizeYMax (0);
   if (aPrevFBOPtr != NULL)
   {
     MyView->FBOGetDimensions (aPrevFBOPtr,
                               aPrevFBOVPSizeX, aPrevFBOVPSizeY,
                               aPrevFBOSizeXMax, aPrevFBOSizeYMax);
-    if (theWidth <= aPrevFBOSizeXMax && theHeight <= aPrevFBOSizeYMax)
+    if (aFBOVPSizeX <= aPrevFBOSizeXMax && aFBOVPSizeY <= aPrevFBOSizeYMax)
     {
-      MyView->FBOChangeViewport (aPrevFBOPtr, theWidth, theHeight);
+      MyView->FBOChangeViewport (aPrevFBOPtr, aFBOVPSizeX, aFBOVPSizeY);
       aFBOPtr = aPrevFBOPtr;
     }
   }
@@ -3550,7 +3551,17 @@ Handle(Image_PixMap) V3d_View::ToPixMap (const Standard_Integer  theWidth,
   if (aFBOPtr == NULL)
   {
     // Try to create hardware accelerated buffer
-    aFBOPtr = MyView->FBOCreate (theWidth, theHeight);
+    aFBOPtr = MyView->FBOCreate (aFBOVPSizeX, aFBOVPSizeY);
+    if (aFBOPtr != NULL)
+    {
+      MyView->FBOGetDimensions (aFBOPtr,
+                                aFBOVPSizeX,  aFBOVPSizeY,
+                                aFBOSizeXMax, aFBOSizeYMax);
+      // reduce viewport in case of hardware limits
+      if (aFBOVPSizeX > aFBOSizeXMax) aFBOVPSizeX = aFBOSizeXMax;
+      if (aFBOVPSizeY > aFBOSizeYMax) aFBOVPSizeY = aFBOSizeYMax;
+      MyView->FBOChangeViewport (aFBOPtr, aFBOVPSizeX, aFBOVPSizeY);
+    }
   }
   cView->ptrFBO = aFBOPtr;
 
@@ -3564,7 +3575,7 @@ Handle(Image_PixMap) V3d_View::ToPixMap (const Standard_Integer  theWidth,
 
     // technically we can reduce existing viewport...
     // but currently allow only dumping the window itself
-    if (theWidth != aWinWidth || theHeight != aWinHeight)
+    if (aFBOVPSizeX != aWinWidth || aFBOVPSizeY != aWinHeight)
     {
       return Handle(Image_PixMap)();
     }
@@ -3583,10 +3594,10 @@ Handle(Image_PixMap) V3d_View::ToPixMap (const Standard_Integer  theWidth,
     //szv: calculate expansion
     Umin = PUmin; Vmin = PVmin; Umax = PUmax; Vmax = PVmax;
     Standard_Real oldWidth = (PUmax - PUmin), oldHeight = (PVmax - PVmin);
-    Standard_Real newWidth = (oldHeight * theWidth) / theHeight;
+    Standard_Real newWidth = (oldHeight * aFBOVPSizeX) / aFBOVPSizeY;
     if (newWidth < oldWidth)
     {
-      Standard_Real newHeight = (oldWidth * theHeight) / theWidth;
+      Standard_Real newHeight = (oldWidth * aFBOVPSizeY) / aFBOVPSizeX;
       // Expand height
       Standard_Real delta = 0.5 * (newHeight - oldHeight);
       Vmin = PVmin - delta;
@@ -3618,7 +3629,7 @@ Handle(Image_PixMap) V3d_View::ToPixMap (const Standard_Integer  theWidth,
 
   // allocate image buffer for dumping
   Image_CRawBufferData aRawBuffer;
-  Handle(Image_PixMap) anImageBitmap = new Image_PixMap (theWidth, theHeight, theBufferType);
+  Handle(Image_PixMap) anImageBitmap = new Image_PixMap (aFBOVPSizeX, aFBOVPSizeY, theBufferType);
   anImageBitmap->AccessBuffer (aRawBuffer);
   if (!MyView->BufferDump (aRawBuffer))
   {
index 85e69b1..6f13b33 100755 (executable)
@@ -855,22 +855,42 @@ static Standard_Integer VDump (Draw_Interpretor& di, Standard_Integer argc, cons
   Handle(AIS_InteractiveContext) IC;
   Handle(V3d_View) view;
   GetCtxAndView (IC, view);
-  if (!view.IsNull())
+  if (view.IsNull())
   {
-    if (aWidth > 0 && aHeight > 0)
-    {
-      return view->ToPixMap (aWidth, aHeight, aBufferType)->Dump (argv[1]) ? 0 : 1;
-    }
-    else
+    di << "Cannot find an active viewer/view\n";
+    return 1;
+  }
+
+  if (aWidth <= 0 || aHeight <= 0)
+  {
+    if (!view->Dump (argv[1], aBufferType))
     {
-      return view->Dump (argv[1], aBufferType) ? 0 : 1;
+      di << "Dumping failed!\n";
+      return 1;
     }
+    return 0;
   }
-  else
+
+  Handle(Image_PixMap) aPixMap = view->ToPixMap (aWidth, aHeight, aBufferType);
+  if (aPixMap.IsNull())
+  {
+    di << "Dumping failed!\n";
+    return 1;
+  }
+
+  Image_CRawBufferData aRawBuffer;
+  aPixMap->AccessBuffer (aRawBuffer);
+  if (aRawBuffer.widthPx != aWidth || aRawBuffer.heightPx != aHeight)
+  {
+    std::cout << "Warning! Dumped dimensions " << aRawBuffer.widthPx << "x" << aRawBuffer.heightPx
+              << " are lesser than requested " << aWidth             << "x" << aHeight << "\n";
+  }
+  if (!aPixMap->Dump (argv[1]))
   {
-    di << "Cannot find an active viewer/view" << "\n";
+    di << "Saving image failed!\n";
     return 1;
   }
+  return 0;
 }
 
 
index b5cd888..530979b 100755 (executable)
@@ -2817,6 +2817,130 @@ static int VMemGpu (Draw_Interpretor& theDI,
   return 0;
 }
 
+// ==============================================================================
+// function : VReadPixel
+// purpose  :
+// ==============================================================================
+static int VReadPixel (Draw_Interpretor& theDI,
+                       Standard_Integer  theArgNb,
+                       const char**      theArgVec)
+{
+  // get the active view
+  Handle(V3d_View) aView = ViewerTest::CurrentView();
+  if (aView.IsNull())
+  {
+    std::cerr << "No active view. Please call vinit.\n";
+    return 1;
+  }
+  else if (theArgNb < 3)
+  {
+    std::cerr << "Usage : " << theArgVec[0] << " xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]\n";
+    return 1;
+  }
+
+  Image_TypeOfImage aBufferType = Image_TOI_RGBA;
+  Standard_Integer aWidth, aHeight;
+  aView->Window()->Size (aWidth, aHeight);
+  const Standard_Integer anX = atoi (theArgVec[1]);
+  const Standard_Integer anY = atoi (theArgVec[2]);
+  if (anX < 0 || anX >= aWidth || anY < 0 || anY > aHeight)
+  {
+    std::cerr << "Pixel coordinates (" << anX << "; " << anY << ") are out of view (" << aWidth << " x " << aHeight << ")\n";
+    return 1;
+  }
+
+  Standard_Boolean toShowName = Standard_False;
+  Standard_Boolean toShowHls  = Standard_False;
+  for (Standard_Integer anIter = 3; anIter < theArgNb; ++anIter)
+  {
+    TCollection_AsciiString aParam (theArgVec[anIter]);
+    if (TCollection_AsciiString::ISSIMILAR      (aParam, TCollection_AsciiString ("rgb")))
+    {
+      aBufferType = Image_TOI_RGB;
+    }
+    else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("hls")))
+    {
+      aBufferType = Image_TOI_RGB;
+      toShowHls   = Standard_True;
+    }
+    else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("rgbf")))
+    {
+      aBufferType = Image_TOI_RGBF;
+    }
+    else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("rgba")))
+    {
+      aBufferType = Image_TOI_RGBA;
+    }
+    else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("rgbaf")))
+    {
+      aBufferType = Image_TOI_RGBAF;
+    }
+    else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("depth")))
+    {
+      aBufferType = Image_TOI_FLOAT;
+    }
+    else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("name")))
+    {
+      toShowName = Standard_True;
+    }
+  }
+
+  Handle(Image_PixMap) anImage = aView->ToPixMap (aWidth, aHeight, aBufferType);
+  if (anImage.IsNull())
+  {
+    std::cerr << "Image dump failed\n";
+    return 1;
+  }
+
+  Quantity_Parameter anAlpha;
+  Quantity_Color aColor = anImage->PixelColor (anX, anY, anAlpha);
+  if (toShowName)
+  {
+    if (aBufferType == Image_TOI_RGBA
+     || aBufferType == Image_TOI_RGBAF)
+    {
+      theDI << Quantity_Color::StringName (aColor.Name()) << " " << anAlpha << "\n";
+    }
+    else
+    {
+      theDI << Quantity_Color::StringName (aColor.Name()) << "\n";
+    }
+  }
+  else
+  {
+    switch (aBufferType)
+    {
+      default:
+      case Image_TOI_RGB:
+      case Image_TOI_RGBF:
+      {
+        if (toShowHls)
+        {
+          theDI << aColor.Hue() << " " << aColor.Light() << " " << aColor.Saturation() << "\n";
+        }
+        else
+        {
+          theDI << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue() << "\n";
+        }
+        break;
+      }
+      case Image_TOI_RGBA:
+      case Image_TOI_RGBAF:
+      {
+        theDI << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue() << " " << anAlpha << "\n";
+        break;
+      }
+      case Image_TOI_FLOAT:
+      {
+        theDI << aColor.Red() << "\n";
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+
 //=======================================================================
 //function : ViewerCommands
 //purpose  :
@@ -2928,4 +3052,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "vmemgpu [f]: print system-dependent GPU memory information if available;"
     " with f option returns free memory in bytes",
     __FILE__, VMemGpu, group);
+  theCommands.Add ("vreadpixel",
+    "vreadpixel xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]"
+    " : Read pixel value for active view",
+    __FILE__, VReadPixel, group);
 }