drawinglayer/source/processor2d/cairopixelprocessor2d.cxx | 38 +++++++++++++- include/vcl/bitmap.hxx | 5 + vcl/source/bitmap/bitmap.cxx | 34 ++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-)
New commits: commit e565a0d634c80a258340f73dc6f4a45cc3e180cc Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Mon Sep 15 17:55:14 2025 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Fri Sep 19 16:56:24 2025 +0200 tdf#168392 Disappearing image fill at lower zoom regression from commit cd93f83bbcba0379bf39f3a4e76b955b7fa368b5 Author: Armin Le Grand (collabora) <armin.legr...@collabora.com> Date: Thu Aug 7 21:02:41 2025 +0200 tdf#167831 avoid painting bitmap data with zero dimensions we cannot skip these fills if the fill bitmap is too small, we need to fill with something or the resulting picture is very wrong Change-Id: I194b59414db8f675df2415c3ee4fb9a0305611b3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190981 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx index ae0931833d6f..9f6b5a2e6ec5 100644 --- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx @@ -2482,7 +2482,43 @@ void CairoPixelProcessor2D::processFillGraphicPrimitive2D( // tdf#167831 check for output size, may have zero discrete dimension in X and/or Y if (0 == nDestWidth || 0 == nDestHeight) { - // it has and is thus invisible + // In which case, maybe we are zoomed out far enough to make the fill bitmap less than one pixel by one pixel, + // and so we need to fill with a color that is an average of the bitmap's color. + basegfx::BColor aFillColor = aPreparedBitmap.GetAverageColor().getBColor(); + bool bTemporaryGrayColorModifier(false); + const DrawModeFlags aDrawModeFlags(getViewInformation2D().getDrawModeFlags()); + if (aDrawModeFlags & DrawModeFlags::GrayBitmap) + { + bTemporaryGrayColorModifier = true; + const basegfx::BColorModifierSharedPtr aBColorModifier( + std::make_shared<basegfx::BColorModifier_gray>()); + maBColorModifierStack.push(aBColorModifier); + } + + if (maBColorModifierStack.count()) + { + // apply ColorModifier to Bitmap data + aFillColor = maBColorModifierStack.getModifiedColor(aFillColor); + + if (bTemporaryGrayColorModifier) + // cleanup temporary BColorModifier + maBColorModifierStack.pop(); + } + + // draw geometry in single color using prepared ReplacementColor + + // use unit geometry as fallback object geometry. Do *not* + // transform, the below used method will use the already + // correctly initialized local ViewInformation + basegfx::B2DPolygon aPolygon(basegfx::utils::createUnitPolygon()); + + // what we still need to apply is the object transform from the + // local primitive, that is not part of DisplayInfo yet + aPolygon.transform(rFillGraphicPrimitive2D.getTransformation()); + + // draw directly, done + paintPolyPolygonRGBA(basegfx::B2DPolyPolygon(aPolygon), aFillColor, + rFillGraphicPrimitive2D.getTransparency()); return; } diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx index de1f27a69f84..b8704fe60095 100644 --- a/include/vcl/bitmap.hxx +++ b/include/vcl/bitmap.hxx @@ -687,6 +687,11 @@ public: [[nodiscard]] Bitmap Modify( const basegfx::BColorModifierStack& rBColorModifierStack) const; + /** Get the average color of the entire image. + i.e. like scaling it down to a 1x1 pixel image. + */ + Color GetAverageColor() const; + [[nodiscard]] static Bitmap AutoScaleBitmap( Bitmap const & rBitmap, const tools::Long aStandardSize ); diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx index 9e769b13cee1..069c9b4b56d3 100644 --- a/vcl/source/bitmap/bitmap.cxx +++ b/vcl/source/bitmap/bitmap.cxx @@ -2141,6 +2141,40 @@ Bitmap Bitmap::Modify(const basegfx::BColorModifierStack& rBColorModifierStack) return aChangedBitmap; } +/** Get the average color of the entire image. + i.e. like scaling it down to a 1x1 pixel image. +*/ +Color Bitmap::GetAverageColor() const +{ + BitmapScopedReadAccess xContent(*this); + assert(xContent); + if(!xContent) + return Color(); + + double fRed = 0; + double fGreen = 0; + double fBlue = 0; + double fAlpha = 0; + int nCnt = 0; + for(tools::Long y(0), nHeight(xContent->Height()); y < nHeight; y++) + { + Scanline pScanline = xContent->GetScanline( y ); + for(tools::Long x(0), nWidth(xContent->Width()); x < nWidth; x++) + { + const BitmapColor aCol(xContent->GetPixelFromData(pScanline, x)); + fRed += aCol.GetRed(); + fGreen += aCol.GetGreen(); + fBlue += aCol.GetBlue(); + fAlpha += aCol.GetAlpha(); + nCnt++; + } + } + return Color(ColorAlpha, static_cast<sal_uInt8>(fAlpha / nCnt), + static_cast<sal_uInt8>(fRed / nCnt), + static_cast<sal_uInt8>(fGreen / nCnt), + static_cast<sal_uInt8>(fBlue / nCnt)); +} + void Bitmap::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const { pOutDev->DrawBitmapEx( rDestPt, *this );