diff options
Diffstat (limited to 'drawinglayer/source/tools')
-rw-r--r-- | drawinglayer/source/tools/converters.cxx | 127 |
1 files changed, 107 insertions, 20 deletions
diff --git a/drawinglayer/source/tools/converters.cxx b/drawinglayer/source/tools/converters.cxx index 3c4ad791a3c3..48a5b404b056 100644 --- a/drawinglayer/source/tools/converters.cxx +++ b/drawinglayer/source/tools/converters.cxx @@ -35,40 +35,114 @@ #include <vcl/filter/PngImageWriter.hxx> #endif -namespace drawinglayer +namespace { -BitmapEx convertToBitmapEx(drawinglayer::primitive2d::Primitive2DContainer&& rSeq, - const geometry::ViewInformation2D& rViewInformation2D, - sal_uInt32 nDiscreteWidth, sal_uInt32 nDiscreteHeight, - sal_uInt32 nMaxSquarePixels) +bool implPrepareConversion(drawinglayer::primitive2d::Primitive2DContainer& rSequence, + sal_uInt32& rnDiscreteWidth, sal_uInt32& rnDiscreteHeight, + const sal_uInt32 nMaxSquarePixels) { - BitmapEx aRetval; - - if (rSeq.empty()) - return aRetval; + if (rSequence.empty()) + return false; - if (nDiscreteWidth <= 0 || nDiscreteHeight <= 0) - return aRetval; + if (rnDiscreteWidth <= 0 || rnDiscreteHeight <= 0) + return false; - // get destination size in pixels - const MapMode aMapModePixel(MapUnit::MapPixel); - const sal_uInt32 nViewVisibleArea(nDiscreteWidth * nDiscreteHeight); - drawinglayer::primitive2d::Primitive2DContainer aSequence(std::move(rSeq)); + const sal_uInt32 nViewVisibleArea(rnDiscreteWidth * rnDiscreteHeight); if (nViewVisibleArea > nMaxSquarePixels) { // reduce render size double fReduceFactor = sqrt(static_cast<double>(nMaxSquarePixels) / static_cast<double>(nViewVisibleArea)); - nDiscreteWidth = basegfx::fround(static_cast<double>(nDiscreteWidth) * fReduceFactor); - nDiscreteHeight = basegfx::fround(static_cast<double>(nDiscreteHeight) * fReduceFactor); + rnDiscreteWidth = basegfx::fround(static_cast<double>(rnDiscreteWidth) * fReduceFactor); + rnDiscreteHeight = basegfx::fround(static_cast<double>(rnDiscreteHeight) * fReduceFactor); const drawinglayer::primitive2d::Primitive2DReference aEmbed( new drawinglayer::primitive2d::TransformPrimitive2D( basegfx::utils::createScaleB2DHomMatrix(fReduceFactor, fReduceFactor), - std::move(aSequence))); + std::move(rSequence))); - aSequence = drawinglayer::primitive2d::Primitive2DContainer{ aEmbed }; + rSequence = drawinglayer::primitive2d::Primitive2DContainer{ aEmbed }; + } + + return true; +} + +AlphaMask implcreateAlphaMask(drawinglayer::primitive2d::Primitive2DContainer& rSequence, + const drawinglayer::geometry::ViewInformation2D& rViewInformation2D, + const Size& rSizePixel) +{ + ScopedVclPtrInstance<VirtualDevice> pContent; + + // prepare vdev + if (!pContent->SetOutputSizePixel(rSizePixel, false)) + { + SAL_WARN("vcl", "Cannot set VirtualDevice to size : " << rSizePixel.Width() << "x" + << rSizePixel.Height()); + return AlphaMask(); + } + + // create pixel processor, also already takes care of AAing and + // checking the getOptionsDrawinglayer().IsAntiAliasing() switch. If + // not wanted, change after this call as needed + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pContentProcessor + = drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(*pContent, + rViewInformation2D); + + // prepare for mask creation + pContent->SetMapMode(MapMode(MapUnit::MapPixel)); + + // set alpha to all white (fully transparent) + pContent->Erase(); + + // embed primitives to paint them black + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::ModifiedColorPrimitive2D( + std::move(rSequence), + std::make_shared<basegfx::BColorModifier_replace>(basegfx::BColor(0.0, 0.0, 0.0)))); + const drawinglayer::primitive2d::Primitive2DContainer xSeq{ xRef }; + + // render + pContentProcessor->process(xSeq); + pContentProcessor.reset(); + + // get alpha channel from vdev + pContent->EnableMapMode(false); + const Point aEmptyPoint; + return AlphaMask(pContent->GetBitmap(aEmptyPoint, rSizePixel)); +} +} + +namespace drawinglayer +{ +AlphaMask createAlphaMask(drawinglayer::primitive2d::Primitive2DContainer&& rSeq, + const geometry::ViewInformation2D& rViewInformation2D, + sal_uInt32 nDiscreteWidth, sal_uInt32 nDiscreteHeight, + sal_uInt32 nMaxSquarePixels) +{ + drawinglayer::primitive2d::Primitive2DContainer aSequence(std::move(rSeq)); + + if (!implPrepareConversion(aSequence, nDiscreteWidth, nDiscreteHeight, nMaxSquarePixels)) + { + return AlphaMask(); + } + + const Size aSizePixel(nDiscreteWidth, nDiscreteHeight); + + return implcreateAlphaMask(aSequence, rViewInformation2D, aSizePixel); +} + +BitmapEx convertToBitmapEx(drawinglayer::primitive2d::Primitive2DContainer&& rSeq, + const geometry::ViewInformation2D& rViewInformation2D, + sal_uInt32 nDiscreteWidth, sal_uInt32 nDiscreteHeight, + sal_uInt32 nMaxSquarePixels) +{ + BitmapEx aRetval; + drawinglayer::primitive2d::Primitive2DContainer aSequence(std::move(rSeq)); + + if (!implPrepareConversion(aSequence, nDiscreteWidth, nDiscreteHeight, nMaxSquarePixels)) + { + return aRetval; } const Point aEmptyPoint; @@ -99,7 +173,7 @@ BitmapEx convertToBitmapEx(drawinglayer::primitive2d::Primitive2DContainer&& rSe } // We map to pixel, use that MapMode. Init by erasing. - pContent->SetMapMode(aMapModePixel); + pContent->SetMapMode(MapMode(MapUnit::MapPixel)); pContent->Erase(); // create pixel processor, also already takes care of AAing and @@ -131,6 +205,19 @@ BitmapEx convertToBitmapEx(drawinglayer::primitive2d::Primitive2DContainer&& rSe } #endif + // Combined/mixed usage of VirtualDevice in Alpha-mode here and + // the faster method for divided content/alpha in the VclPixelProcessor2D + // *can* go wrong e.g. for objects filled with TransparenceGradients, + // so unfortunately for now we have to reliably re-create the + // AlphaMask using a method that does this always correct (also used + // now in GlowPrimitive2D and ShadowPrimitive2D which both only need the + // AlphaMask to do their job, so speeding that up, too). + // Note: This could be further approved by creating a small ::B2DProcessor + // that checks if rSeq contains a TransparenceGradient fill and only then use + // this correction. + const AlphaMask aAlpha(implcreateAlphaMask(aSequence, rViewInformation2D, aSizePixel)); + aRetval = BitmapEx(aRetval.GetBitmap(), aAlpha); + return aRetval; } |