drawinglayer/source/tools/converters.cxx | 179 +++++++++++-------------------- 1 file changed, 68 insertions(+), 111 deletions(-)
New commits: commit 3d4895e0720f5f0f5dc748470bd42d0aba2f6244 Author: Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de> AuthorDate: Fri Sep 2 19:15:13 2022 +0200 Commit: Armin Le Grand <armin.le.gr...@me.com> CommitDate: Wed Sep 7 10:33:11 2022 +0200 ConvertToBitmapEx slightly too bright if transparency involved Stumbled about this error when working on re-designing the blend primitives for shapes. Using convertToBitmapEx is the base for these (also for the UNO API conversion from Primitives to BitmapEx). Use a VirtualDevice in the Alpha-mode now to solve it. This creates the needed alpha channel 'in parallel'. It is not cheaper though since the VDev in that mode internally uses two VDevs, so ressoure-wise it's more expensive, speed-wise pretty much the same (the former two-path rendering created content & alpha separately in two runs). The former method always created the correct Alpha, but when transparent geometry is involved, the created content was blended against white (COL_WHITE) due to the starting conditions of the content creation. There are more ways than using a VirtualDevice in the Alpha-mode, to do this correctly, but this is the most simple for now - and I was persuaded by the following argument: Due to hoping to be able to render to RGBA in the future anyways there is no need to experiment trying to do the correct thing using an expanded version of the former method. Change-Id: I23e005f9c3723059e2b88660fede09aa83844b38 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139272 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> diff --git a/drawinglayer/source/tools/converters.cxx b/drawinglayer/source/tools/converters.cxx index 7dc1259edfaa..6139fb296d71 100644 --- a/drawinglayer/source/tools/converters.cxx +++ b/drawinglayer/source/tools/converters.cxx @@ -37,7 +37,6 @@ namespace drawinglayer { - BitmapEx convertToBitmapEx( drawinglayer::primitive2d::Primitive2DContainer&& rSeq, const geometry::ViewInformation2D& rViewInformation2D, @@ -47,132 +46,90 @@ namespace drawinglayer { BitmapEx aRetval; - if(!rSeq.empty() && nDiscreteWidth && nDiscreteHeight) - { - // get destination size in pixels - const MapMode aMapModePixel(MapUnit::MapPixel); - const sal_uInt32 nViewVisibleArea(nDiscreteWidth * nDiscreteHeight); - drawinglayer::primitive2d::Primitive2DContainer aSequence; + if(rSeq.empty()) + return aRetval; - 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); + if(nDiscreteWidth <= 0 || nDiscreteHeight <= 0) + return aRetval; - const drawinglayer::primitive2d::Primitive2DReference aEmbed( - new drawinglayer::primitive2d::TransformPrimitive2D( - basegfx::utils::createScaleB2DHomMatrix(fReduceFactor, fReduceFactor), - std::move(rSeq))); + // get destination size in pixels + const MapMode aMapModePixel(MapUnit::MapPixel); + const sal_uInt32 nViewVisibleArea(nDiscreteWidth * nDiscreteHeight); + drawinglayer::primitive2d::Primitive2DContainer aSequence(std::move(rSeq)); - aSequence = drawinglayer::primitive2d::Primitive2DContainer { aEmbed }; - } - else - aSequence = std::move(rSeq); + 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); - const Point aEmptyPoint; - const Size aSizePixel(nDiscreteWidth, nDiscreteHeight); - ScopedVclPtrInstance< VirtualDevice > pContent; + const drawinglayer::primitive2d::Primitive2DReference aEmbed( + new drawinglayer::primitive2d::TransformPrimitive2D( + basegfx::utils::createScaleB2DHomMatrix(fReduceFactor, fReduceFactor), + std::move(aSequence))); - // prepare vdev - if (!pContent->SetOutputSizePixel(aSizePixel, false)) - { - SAL_WARN("vcl", "Cannot set VirtualDevice to size : " << aSizePixel.Width() << "x" << aSizePixel.Height()); - return aRetval; - } - pContent->SetMapMode(aMapModePixel); + aSequence = drawinglayer::primitive2d::Primitive2DContainer { aEmbed }; + } - // set to all white - pContent->SetBackground(Wallpaper(COL_WHITE)); - pContent->Erase(); + const Point aEmptyPoint; + const Size aSizePixel(nDiscreteWidth, nDiscreteHeight); + + // Create target VirtualDevice. Use a VirtualDevice in the Alpha-mode. + // This creates the needed alpha channel 'in parallel'. It is not + // cheaper though since the VDev in that mode internally uses two VDevs, + // so ressoure-wise it's more expensive, speed-wise pretty much the same + // (the former two-path rendering created content & alpha separately in + // two runs). The former method always created the correct Alpha, but + // when transparent geometry was involved, the created content was + // blended against white (COL_WHITE) due to the starting conditions of + // creation. + // There are more ways than this to do this correctly, but this is the + // most simple for now. Due to hoping to be able to render to RGBA in the + // future anyways there is no need to experiment trying to do the correct + // thing using an expanded version of the former method. + ScopedVclPtrInstance<VirtualDevice> pContent( + *Application::GetDefaultDevice(), DeviceFormat::DEFAULT, DeviceFormat::DEFAULT); + + // prepare vdev + if (!pContent->SetOutputSizePixel(aSizePixel, false)) + { + SAL_WARN("vcl", "Cannot set VirtualDevice to size : " << aSizePixel.Width() << "x" << aSizePixel.Height()); + return aRetval; + } - // 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<processor2d::BaseProcessor2D> pContentProcessor = processor2d::createPixelProcessor2DFromOutputDevice( - *pContent, - rViewInformation2D); + // We map to pixel, use that MapMode. Init by erasing. + pContent->SetMapMode(aMapModePixel); + pContent->Erase(); -#ifdef DBG_UTIL - static bool bDoSaveForVisualControl(false); // loplugin:constvars:ignore -#endif - // render content - pContentProcessor->process(aSequence); + // 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<processor2d::BaseProcessor2D> pContentProcessor = processor2d::createPixelProcessor2DFromOutputDevice( + *pContent, + rViewInformation2D); - // get content - pContent->EnableMapMode(false); - const Bitmap aContent(pContent->GetBitmap(aEmptyPoint, aSizePixel)); + // render content + pContentProcessor->process(aSequence); -#ifdef DBG_UTIL - if(bDoSaveForVisualControl) - { - SvFileStream aNew( -#ifdef _WIN32 - "c:\\test_content.png" -#else - "~/test_content.png" -#endif - , StreamMode::WRITE|StreamMode::TRUNC); - BitmapEx aContentEx(aContent); - vcl::PngImageWriter aPNGWriter(aNew); - aPNGWriter.write(aContentEx); - } -#endif - // prepare for mask creation - pContent->SetMapMode(aMapModePixel); - - // set alpha to all white (fully transparent) - pContent->Erase(); - - // embed primitives to paint them black - const primitive2d::Primitive2DReference xRef( - new primitive2d::ModifiedColorPrimitive2D( - std::move(aSequence), - std::make_shared<basegfx::BColorModifier_replace>( - basegfx::BColor(0.0, 0.0, 0.0)))); - const primitive2d::Primitive2DContainer xSeq { xRef }; - - // render - pContentProcessor->process(xSeq); - pContentProcessor.reset(); - - // get alpha channel from vdev - pContent->EnableMapMode(false); - const Bitmap aAlpha(pContent->GetBitmap(aEmptyPoint, aSizePixel)); -#ifdef DBG_UTIL - if(bDoSaveForVisualControl) - { - SvFileStream aNew( -#ifdef _WIN32 - "c:\\test_alpha.png" -#else - "~/test_alpha.png" -#endif - , StreamMode::WRITE|StreamMode::TRUNC); - BitmapEx aAlphaEx(aAlpha); - vcl::PngImageWriter aPNGWriter(aNew); - aPNGWriter.write(aAlphaEx); - } -#endif + // create final BitmapEx result + aRetval = pContent->GetBitmapEx(aEmptyPoint, aSizePixel); - // create BitmapEx result - aRetval = BitmapEx(aContent, AlphaMask(aAlpha)); #ifdef DBG_UTIL - if(bDoSaveForVisualControl) - { - SvFileStream aNew( + static bool bDoSaveForVisualControl(false); // loplugin:constvars:ignore + if(bDoSaveForVisualControl) + { + SvFileStream aNew( #ifdef _WIN32 - "c:\\test_combined.png" + "c:\\test_combined.png" #else - "~/test_combined.png" -#endif - , StreamMode::WRITE|StreamMode::TRUNC); - vcl::PngImageWriter aPNGWriter(aNew); - aPNGWriter.write(aRetval); - } + "~/test_combined.png" #endif + , StreamMode::WRITE|StreamMode::TRUNC); + vcl::PngImageWriter aPNGWriter(aNew); + aPNGWriter.write(aRetval); } +#endif return aRetval; }