diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2019-10-10 09:49:29 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2019-10-10 13:35:24 +0200 |
commit | 55b4d5ea9e1a42edf71d2eef6028830983dbc11c (patch) | |
tree | 9c2bbdf69591d6575440d50fd0f452bd776803d8 /vcl | |
parent | 91c586e10c816340523bf1c4df910dd2538c9fee (diff) |
vcl: only smooth bitmap transform when needed
If you have a very small bitmap and you rotate it by 90 degrees, then
smoothing is not needed, but the result will be blurry. So in case
scaling / shear doesn't need it and we do 90/180/270 rotation, avoid
smoothing.
Change-Id: I4b8fad4b0b70516d35eaecfa70a707e6e8362d18
Reviewed-on: https://gerrit.libreoffice.org/80589
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/CppunitTest_vcl_bitmap_test.mk | 1 | ||||
-rw-r--r-- | vcl/qa/cppunit/BitmapExTest.cxx | 40 | ||||
-rw-r--r-- | vcl/source/gdi/bitmapex.cxx | 37 |
3 files changed, 76 insertions, 2 deletions
diff --git a/vcl/CppunitTest_vcl_bitmap_test.mk b/vcl/CppunitTest_vcl_bitmap_test.mk index 90db22099b40..9ebef12dcfb2 100644 --- a/vcl/CppunitTest_vcl_bitmap_test.mk +++ b/vcl/CppunitTest_vcl_bitmap_test.mk @@ -33,6 +33,7 @@ $(eval $(call gb_CppunitTest_set_include,vcl_bitmap_test,\ )) $(eval $(call gb_CppunitTest_use_libraries,vcl_bitmap_test, \ + basegfx \ comphelper \ cppu \ cppuhelper \ diff --git a/vcl/qa/cppunit/BitmapExTest.cxx b/vcl/qa/cppunit/BitmapExTest.cxx index 3a89441b9604..23f40f0013cd 100644 --- a/vcl/qa/cppunit/BitmapExTest.cxx +++ b/vcl/qa/cppunit/BitmapExTest.cxx @@ -12,6 +12,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <vcl/bitmapex.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> #include <bitmapwriteaccess.hxx> #include <svdata.hxx> #include <salinst.hxx> @@ -22,10 +23,12 @@ class BitmapExTest : public CppUnit::TestFixture { void testGetPixelColor24_8(); void testGetPixelColor32(); + void testTransformBitmapEx(); CPPUNIT_TEST_SUITE(BitmapExTest); CPPUNIT_TEST(testGetPixelColor24_8); CPPUNIT_TEST(testGetPixelColor32); + CPPUNIT_TEST(testTransformBitmapEx); CPPUNIT_TEST_SUITE_END(); }; @@ -66,6 +69,43 @@ void BitmapExTest::testGetPixelColor32() CPPUNIT_ASSERT_EQUAL(Color(0xAA, 0x00, 0xFF, 0x00), aBitmapEx.GetPixelColor(0, 0)); } +void BitmapExTest::testTransformBitmapEx() +{ + Bitmap aBitmap(Size(16, 16), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(COL_WHITE); + for (int i = 0; i < 8; ++i) + { + for (int j = 0; j < 8; ++j) + { + pWriteAccess->SetPixel(i, j, COL_BLACK); + } + } + } + BitmapEx aBitmapEx(aBitmap); + + basegfx::B2DHomMatrix aMatrix; + aMatrix.rotate(M_PI / 2); + BitmapEx aTransformed = aBitmapEx.TransformBitmapEx(16, 16, aMatrix); + aBitmap = aTransformed.GetBitmap(); + Bitmap::ScopedReadAccess pAccess(aBitmap); + for (int i = 0; i < 16; ++i) + { + for (int j = 0; j < 16; ++j) + { + BitmapColor aColor = pAccess->GetPixel(i, j); + std::stringstream ss; + ss << "Color is expected to be white or black, is '" << aColor.AsRGBHexString() << "'"; + // Without the accompanying fix in place, this test would have failed with: + // - Expression: aColor == COL_WHITE || aColor == COL_BLACK + // - Color is expected to be white or black, is 'bfbfbf' + // i.e. smoothing introduced noise for a simple 90 deg rotation. + CPPUNIT_ASSERT_MESSAGE(ss.str(), aColor == COL_WHITE || aColor == COL_BLACK); + } + } +} + } // namespace CPPUNIT_TEST_SUITE_REGISTRATION(BitmapExTest); diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx index d4f96bcd86f3..5e410d05fb9b 100644 --- a/vcl/source/gdi/bitmapex.cxx +++ b/vcl/source/gdi/bitmapex.cxx @@ -867,6 +867,38 @@ namespace return aDestination; } + + /// Decides if rTransformation needs smoothing or not (e.g. 180 deg rotation doesn't need it). + bool implTransformNeedsSmooth(const basegfx::B2DHomMatrix& rTransformation) + { + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + rTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + if (aScale != basegfx::B2DVector(1, 1)) + { + return true; + } + + fRotate = fmod( fRotate, F_2PI ); + if (fRotate < 0) + { + fRotate += F_2PI; + } + if (!rtl::math::approxEqual(fRotate, 0) + && !rtl::math::approxEqual(fRotate, F_PI2) + && !rtl::math::approxEqual(fRotate, F_PI) + && !rtl::math::approxEqual(fRotate, 3 * F_PI2)) + { + return true; + } + + if (!rtl::math::approxEqual(fShearX, 0)) + { + return true; + } + + return false; + } } // end of anonymous namespace BitmapEx BitmapEx::TransformBitmapEx( @@ -879,14 +911,15 @@ BitmapEx BitmapEx::TransformBitmapEx( // force destination to 24 bit, we want to smooth output const Size aDestinationSize(basegfx::fround(fWidth), basegfx::fround(fHeight)); - const Bitmap aDestination(impTransformBitmap(GetBitmapRef(), aDestinationSize, rTransformation, /*bSmooth*/true)); + bool bSmooth = implTransformNeedsSmooth(rTransformation); + const Bitmap aDestination(impTransformBitmap(GetBitmapRef(), aDestinationSize, rTransformation, bSmooth)); // create mask if(IsTransparent()) { if(IsAlpha()) { - const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, /*bSmooth*/true)); + const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, bSmooth)); return BitmapEx(aDestination, AlphaMask(aAlpha)); } else |