vcl/qa/cppunit/outdev.cxx | 33 +++++++++++++++++++++++++++++++++ vcl/source/outdev/bitmapex.cxx | 11 +++++++++++ 2 files changed, 44 insertions(+)
New commits: commit cdd4166b9445f99c5e404393407f31b8072a06ab Author: Miklos Vajna <[email protected]> AuthorDate: Thu Sep 25 08:48:07 2025 +0200 Commit: Caolán McNamara <[email protected]> CommitDate: Thu Sep 25 12:05:17 2025 +0200 tdf#166338 vcl: avoid unwanted downscale in DrawTransformedBitmapEx() Open the Impress bugdoc, the "Annotated result:" image's "red cable" bitmap is sharp in edit mode, but is blurry when presenting. This went wrong in commit 7c94d7267bc8b5f43185204ab4953c4b188214bf (tdf#149943 vcl: fix pixelated PDF export and print for a rotated image, 2022-08-03), which stopped changing the scale part of the transform matrix. The old problem was that the transform resulted in a downscale: debug:5739:5739: OutputDevice::DrawTransformedBitmapEx: aOriginalScale w,h is 226,100, aFullScale is (906.698,6277.69) -> for w, we go from 906 to 226 The new use-case is that this transform used to upscale in the past, which preserved more pixels from the original bitmap: debug:5632:5632: OutputDevice::DrawTransformedBitmapEx: aOriginalScale w,h is 326,1125, aFullScale is (21.1276,76.1197) -> for w, we go from 21 to 326 Fix the problem by conditionally restore the change of the scale in the transform matrix: only do it when we would upscale. This was the presented bitmap is sharp again, but the old use-case continues to work. The deeper problem is why slideshow goes via a metafile at all, but that's not changed here. Change-Id: I73ef426dc9d047a0231a700b0fe7ed0e4747d81b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191473 Tested-by: Caolán McNamara <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Caolán McNamara <[email protected]> diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx index 67489665ebbb..7fb6c9ace0db 100644 --- a/vcl/qa/cppunit/outdev.cxx +++ b/vcl/qa/cppunit/outdev.cxx @@ -17,6 +17,7 @@ #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <basegfx/vector/b2enums.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <vcl/gradient.hxx> #include <vcl/lineinfo.hxx> @@ -339,6 +340,38 @@ CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawGrayBitmap) } } +CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawTransformedBitmapExScale) +{ + // Given a 100x100 bitmap: + ScopedVclPtrInstance<VirtualDevice> pVDev; + Bitmap aBitmap(Size(100, 100), vcl::PixelFormat::N24_BPP); + basegfx::B2DVector aScale(20, 80); + basegfx::B2DVector aTranslate(80, 0); + double fRotate = M_PI / 2; + double fShearX = 0; + basegfx::B2DHomMatrix aMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( + aScale, fShearX, fRotate, aTranslate); + BitmapEx aBitmapEx(aBitmap); + GDIMetaFile aMtf; + aMtf.Record(pVDev.get()); + + // When drawing that with a transform: + pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx); + + // Then make sure the bitmap recorded in the metafile doesn't get a scaled down width: + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aMtf.GetActionSize()); + MetaAction* pAction = aMtf.GetAction(0); + CPPUNIT_ASSERT_EQUAL(MetaActionType::BMPEXSCALE, pAction->GetType()); + auto pBitmapAction = static_cast<MetaBmpExScaleAction*>(pAction); + const BitmapEx& rBitmapEx = pBitmapAction->GetBitmapEx(); + Size aTransformedSize = rBitmapEx.GetSizePixel(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected greater or equal than: 100 + // - Actual : 80 + // i.e. an unwanted scaling down lead to blurry presentation output. + CPPUNIT_ASSERT_GREATEREQUAL(static_cast<tools::Long>(100), aTransformedSize.getWidth()); +} + CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawTransformedBitmapEx) { // Create a virtual device, and connect a metafile to it. diff --git a/vcl/source/outdev/bitmapex.cxx b/vcl/source/outdev/bitmapex.cxx index 3024b7ba86ed..3d6b4ff28727 100644 --- a/vcl/source/outdev/bitmapex.cxx +++ b/vcl/source/outdev/bitmapex.cxx @@ -540,6 +540,17 @@ void OutputDevice::DrawTransformedBitmapEx( basegfx::B2DVector aFullScale, aFullTranslate; double fFullRotate, fFullShearX; aFullTransform.decompose(aFullScale, aFullTranslate, fFullRotate, fFullShearX); + if (aFullScale.getX() > 0 && aFullScale.getY() > 0 + && rOriginalSizePixel.getWidth() > aFullScale.getX() + && rOriginalSizePixel.getHeight() > aFullScale.getY()) + { + // aFullTransform would downscale the bitmap: avoid this, so the recorded metafile can be + // better upscaled later. + basegfx::B2DHomMatrix aTransform = basegfx::utils::createScaleB2DHomMatrix( + rOriginalSizePixel.getWidth() / aFullScale.getX(), + rOriginalSizePixel.getHeight() / aFullScale.getY()); + aFullTransform *= aTransform; + } double fSourceRatio = 1.0; if (rOriginalSizePixel.getHeight() != 0)
