summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2019-10-10 09:49:29 +0200
committerMiklos Vajna <vmiklos@collabora.com>2019-10-10 13:35:24 +0200
commit55b4d5ea9e1a42edf71d2eef6028830983dbc11c (patch)
tree9c2bbdf69591d6575440d50fd0f452bd776803d8 /vcl
parent91c586e10c816340523bf1c4df910dd2538c9fee (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.mk1
-rw-r--r--vcl/qa/cppunit/BitmapExTest.cxx40
-rw-r--r--vcl/source/gdi/bitmapex.cxx37
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