From 85e096c3df7e12e72ba4f04e2dfc42ee02621d1f Mon Sep 17 00:00:00 2001 From: vro Date: Fri, 22 Jun 2012 11:29:55 +0400 Subject: [PATCH] 0023156: Image_PixMap::PixelColor() extended to return alpha value 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 | 16 ++- src/Image/Image_PixMap.cxx | 32 ++++- src/V3d/V3d_View.cxx | 25 +++- src/ViewerTest/ViewerTest.cxx | 38 ++++-- src/ViewerTest/ViewerTest_ViewerCommands.cxx | 128 +++++++++++++++++++ 5 files changed, 218 insertions(+), 21 deletions(-) diff --git a/src/Image/Image_PixMap.cdl b/src/Image/Image_PixMap.cdl index 8bf6ffcfaf..ad528f3721 100644 --- a/src/Image/Image_PixMap.cdl +++ b/src/Image/Image_PixMap.cdl @@ -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; diff --git a/src/Image/Image_PixMap.cxx b/src/Image/Image_PixMap.cxx index a0927fd422..3065861294 100644 --- a/src/Image/Image_PixMap.cxx +++ b/src/Image/Image_PixMap.cxx @@ -120,9 +120,11 @@ } 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 } diff --git a/src/V3d/V3d_View.cxx b/src/V3d/V3d_View.cxx index 4dc97ec514..04df995a20 100755 --- a/src/V3d/V3d_View.cxx +++ b/src/V3d/V3d_View.cxx @@ -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)) { diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 85e69b1241..6f13b33758 100755 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -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; } diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index b5cd888fe9..530979b9d0 100755 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -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); } -- 2.20.1