diff options
-rw-r--r-- | vcl/qa/cppunit/BitmapTest.cxx | 65 | ||||
-rw-r--r-- | vcl/source/bitmap/bitmappaint.cxx | 140 |
2 files changed, 173 insertions, 32 deletions
diff --git a/vcl/qa/cppunit/BitmapTest.cxx b/vcl/qa/cppunit/BitmapTest.cxx index 0c96977a880a..e6c95d27b954 100644 --- a/vcl/qa/cppunit/BitmapTest.cxx +++ b/vcl/qa/cppunit/BitmapTest.cxx @@ -45,6 +45,7 @@ class BitmapTest : public CppUnit::TestFixture void testOctree(); void testEmptyAccess(); void testDitherSize(); + void testMirror(); CPPUNIT_TEST_SUITE(BitmapTest); CPPUNIT_TEST(testCreation); @@ -61,6 +62,7 @@ class BitmapTest : public CppUnit::TestFixture CPPUNIT_TEST(testOctree); CPPUNIT_TEST(testEmptyAccess); CPPUNIT_TEST(testDitherSize); + CPPUNIT_TEST(testMirror); CPPUNIT_TEST_SUITE_END(); }; @@ -682,6 +684,69 @@ void BitmapTest::testDitherSize() } } +void BitmapTest::testMirror() +{ + for (int bpp : { 4, 8, 24, 32 }) + { + Bitmap bitmap(Size(11, 11), bpp); + { + bitmap.Erase(COL_MAGENTA); + BitmapWriteAccess write(bitmap); + if (write.HasPalette()) + { + // Note that SetPixel() and GetColor() take arguments as Y,X. + write.SetPixel(0, 0, BitmapColor(write.GetBestPaletteIndex(COL_BLACK))); + write.SetPixel(10, 0, BitmapColor(write.GetBestPaletteIndex(COL_WHITE))); + write.SetPixel(0, 10, BitmapColor(write.GetBestPaletteIndex(COL_RED))); + write.SetPixel(10, 10, BitmapColor(write.GetBestPaletteIndex(COL_BLUE))); + write.SetPixel(5, 0, BitmapColor(write.GetBestPaletteIndex(COL_GREEN))); + write.SetPixel(0, 5, BitmapColor(write.GetBestPaletteIndex(COL_YELLOW))); + } + else + { + write.SetPixel(0, 0, COL_BLACK); + write.SetPixel(10, 0, COL_WHITE); + write.SetPixel(0, 10, COL_RED); + write.SetPixel(10, 10, COL_BLUE); + write.SetPixel(5, 0, COL_GREEN); + write.SetPixel(0, 5, COL_YELLOW); + } + } + bitmap.Mirror(BmpMirrorFlags::Horizontal); + { + BitmapReadAccess read(bitmap); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), read.GetColor(0, 10)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), read.GetColor(10, 10)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED), read.GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE), read.GetColor(10, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN), read.GetColor(5, 10)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW), read.GetColor(0, 5)); + } + bitmap.Mirror(BmpMirrorFlags::Vertical); + { + BitmapReadAccess read(bitmap); + // Now is effectively mirrored in both directions. + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), read.GetColor(10, 10)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), read.GetColor(0, 10)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED), read.GetColor(10, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE), read.GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN), read.GetColor(5, 10)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW), read.GetColor(10, 5)); + } + bitmap.Mirror(BmpMirrorFlags::Vertical | BmpMirrorFlags::Horizontal); + { + BitmapReadAccess read(bitmap); + // Now is back the original. + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), read.GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), read.GetColor(10, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED), read.GetColor(0, 10)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE), read.GetColor(10, 10)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN), read.GetColor(5, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW), read.GetColor(0, 5)); + } + } +} + } // namespace CPPUNIT_TEST_SUITE_REGISTRATION(BitmapTest); diff --git a/vcl/source/bitmap/bitmappaint.cxx b/vcl/source/bitmap/bitmappaint.cxx index b69972788746..ad20832022d5 100644 --- a/vcl/source/bitmap/bitmappaint.cxx +++ b/vcl/source/bitmap/bitmappaint.cxx @@ -105,6 +105,28 @@ bool Bitmap::Invert() return bRet; } +namespace +{ +// Put each scanline's content horizontally mirrored into the other one. +// (optimized version accessing pixel values directly). +template <int bitCount> +void mirrorScanlines(Scanline scanline1, Scanline scanline2, tools::Long nWidth) +{ + constexpr int byteCount = bitCount / 8; + Scanline pos1 = scanline1; + Scanline pos2 = scanline2 + (nWidth - 1) * byteCount; // last in second scanline + sal_uInt8 tmp[byteCount]; + for (tools::Long i = 0; i < nWidth; ++i) + { + memcpy(tmp, pos1, byteCount); + memcpy(pos1, pos2, byteCount); + memcpy(pos2, tmp, byteCount); + pos1 += byteCount; + pos2 -= byteCount; + } +} +} + bool Bitmap::Mirror(BmpMirrorFlags nMirrorFlags) { bool bHorz(nMirrorFlags & BmpMirrorFlags::Horizontal); @@ -120,18 +142,40 @@ bool Bitmap::Mirror(BmpMirrorFlags nMirrorFlags) const tools::Long nWidth = pAcc->Width(); const tools::Long nHeight = pAcc->Height(); const tools::Long nWidth1 = nWidth - 1; - const tools::Long nWidth_2 = nWidth >> 1; + const tools::Long nWidth_2 = nWidth / 2; + const tools::Long nSecondHalf = nWidth - nWidth_2; - for (tools::Long nY = 0; nY < nHeight; nY++) + switch (pAcc->GetBitCount()) { - Scanline pScanline = pAcc->GetScanline(nY); - for (tools::Long nX = 0, nOther = nWidth1; nX < nWidth_2; nX++, nOther--) - { - const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX)); + // Special-case these, swap the halves of scanlines while mirroring them. + case 32: + for (tools::Long nY = 0; nY < nHeight; nY++) + mirrorScanlines<32>(pAcc->GetScanline(nY), + pAcc->GetScanline(nY) + 4 * nSecondHalf, nWidth_2); + break; + case 24: + for (tools::Long nY = 0; nY < nHeight; nY++) + mirrorScanlines<24>(pAcc->GetScanline(nY), + pAcc->GetScanline(nY) + 3 * nSecondHalf, nWidth_2); + break; + case 8: + for (tools::Long nY = 0; nY < nHeight; nY++) + mirrorScanlines<8>(pAcc->GetScanline(nY), + pAcc->GetScanline(nY) + nSecondHalf, nWidth_2); + break; + default: + for (tools::Long nY = 0; nY < nHeight; nY++) + { + Scanline pScanline = pAcc->GetScanline(nY); + for (tools::Long nX = 0, nOther = nWidth1; nX < nWidth_2; nX++, nOther--) + { + const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX)); - pAcc->SetPixelOnData(pScanline, nX, pAcc->GetPixelFromData(pScanline, nOther)); - pAcc->SetPixelOnData(pScanline, nOther, aTemp); - } + pAcc->SetPixelOnData(pScanline, nX, + pAcc->GetPixelFromData(pScanline, nOther)); + pAcc->SetPixelOnData(pScanline, nOther, aTemp); + } + } } pAcc.reset(); @@ -170,33 +214,65 @@ bool Bitmap::Mirror(BmpMirrorFlags nMirrorFlags) const tools::Long nWidth = pAcc->Width(); const tools::Long nWidth1 = nWidth - 1; const tools::Long nHeight = pAcc->Height(); - tools::Long nHeight_2 = nHeight >> 1; + tools::Long nHeight_2 = nHeight / 2; + const tools::Long nWidth_2 = nWidth / 2; + const tools::Long nSecondHalf = nWidth - nWidth_2; - for (tools::Long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY--) + switch (pAcc->GetBitCount()) { - Scanline pScanline = pAcc->GetScanline(nY); - Scanline pScanlineOther = pAcc->GetScanline(nOtherY); - for (tools::Long nX = 0, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX--) - { - const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX)); + case 32: + for (tools::Long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY--) + mirrorScanlines<32>(pAcc->GetScanline(nY), pAcc->GetScanline(nOtherY), + nWidth); + if (nHeight & 1) + mirrorScanlines<32>(pAcc->GetScanline(nHeight_2), + pAcc->GetScanline(nHeight_2) + 4 * nSecondHalf, + nWidth_2); + break; + case 24: + for (tools::Long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY--) + mirrorScanlines<24>(pAcc->GetScanline(nY), pAcc->GetScanline(nOtherY), + nWidth); + if (nHeight & 1) + mirrorScanlines<24>(pAcc->GetScanline(nHeight_2), + pAcc->GetScanline(nHeight_2) + 3 * nSecondHalf, + nWidth_2); + break; + case 8: + for (tools::Long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY--) + mirrorScanlines<8>(pAcc->GetScanline(nY), pAcc->GetScanline(nOtherY), + nWidth); + if (nHeight & 1) + mirrorScanlines<8>(pAcc->GetScanline(nHeight_2), + pAcc->GetScanline(nHeight_2) + nSecondHalf, nWidth_2); + break; + default: + for (tools::Long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY--) + { + Scanline pScanline = pAcc->GetScanline(nY); + Scanline pScanlineOther = pAcc->GetScanline(nOtherY); + for (tools::Long nX = 0, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX--) + { + const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX)); - pAcc->SetPixelOnData(pScanline, nX, - pAcc->GetPixelFromData(pScanlineOther, nOtherX)); - pAcc->SetPixelOnData(pScanlineOther, nOtherX, aTemp); - } - } + pAcc->SetPixelOnData(pScanline, nX, + pAcc->GetPixelFromData(pScanlineOther, nOtherX)); + pAcc->SetPixelOnData(pScanlineOther, nOtherX, aTemp); + } + } - // if necessary, also mirror the middle line horizontally - if (nHeight & 1) - { - Scanline pScanline = pAcc->GetScanline(nHeight_2); - for (tools::Long nX = 0, nOtherX = nWidth1, nWidth_2 = nWidth >> 1; nX < nWidth_2; - nX++, nOtherX--) - { - const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX)); - pAcc->SetPixelOnData(pScanline, nX, pAcc->GetPixelFromData(pScanline, nOtherX)); - pAcc->SetPixelOnData(pScanline, nOtherX, aTemp); - } + // if necessary, also mirror the middle line horizontally + if (nHeight & 1) + { + Scanline pScanline = pAcc->GetScanline(nHeight_2); + for (tools::Long nX = 0, nOtherX = nWidth1; nX < nWidth_2; nX++, nOtherX--) + { + const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX)); + pAcc->SetPixelOnData(pScanline, nX, + pAcc->GetPixelFromData(pScanline, nOtherX)); + pAcc->SetPixelOnData(pScanline, nOtherX, aTemp); + } + } } pAcc.reset(); |