nss: upgrade to release 3.73
[LibreOffice.git] / vcl / qa / cppunit / BitmapScaleTest.cxx
blob7de2f7d8678d8dd576290955a6fd02f2819161aa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <cppunit/TestAssert.h>
11 #include <cppunit/TestFixture.h>
12 #include <cppunit/extensions/HelperMacros.h>
14 #include <vcl/bitmap.hxx>
15 #include <vcl/bitmapaccess.hxx>
17 #include <tools/stream.hxx>
18 #include <vcl/graphicfilter.hxx>
20 #include <BitmapSymmetryCheck.hxx>
21 #include <bitmapwriteaccess.hxx>
23 namespace
25 class BitmapScaleTest : public CppUnit::TestFixture
27 void testScale();
28 void testScale2();
29 void testScaleSymmetry();
31 CPPUNIT_TEST_SUITE(BitmapScaleTest);
32 CPPUNIT_TEST(testScale);
33 CPPUNIT_TEST(testScale2);
34 CPPUNIT_TEST(testScaleSymmetry);
35 CPPUNIT_TEST_SUITE_END();
38 bool checkBitmapColor(Bitmap const& rBitmap, Color const& rExpectedColor)
40 bool bResult = true;
41 Bitmap aBitmap(rBitmap);
42 Bitmap::ScopedReadAccess pReadAccess(aBitmap);
43 tools::Long nHeight = pReadAccess->Height();
44 tools::Long nWidth = pReadAccess->Width();
45 for (tools::Long y = 0; y < nHeight; ++y)
47 Scanline pScanlineRead = pReadAccess->GetScanline(y);
48 for (tools::Long x = 0; x < nWidth; ++x)
50 Color aColor = pReadAccess->GetPixelFromData(pScanlineRead, x);
51 if (aColor != rExpectedColor)
52 bResult = false;
56 return bResult;
59 void assertColorsAreSimilar(int maxDifference, const std::string& message,
60 const BitmapColor& expected, const BitmapColor& actual)
62 // Check that the two colors match or are reasonably similar.
63 if (expected == actual)
64 return;
65 if (abs(expected.GetRed() - actual.GetRed()) <= maxDifference
66 && abs(expected.GetGreen() - actual.GetGreen()) <= maxDifference
67 && abs(expected.GetBlue() - actual.GetBlue()) <= maxDifference
68 && abs(expected.GetAlpha() - actual.GetAlpha()) <= maxDifference)
70 return;
72 CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual);
75 void assertColorsAreSimilar(int maxDifference, int line, const BitmapColor& expected,
76 const BitmapColor& actual)
78 std::stringstream stream;
79 stream << "Line: " << line;
80 assertColorsAreSimilar(maxDifference, stream.str(), expected, actual);
83 void BitmapScaleTest::testScale()
85 const bool bExportBitmap(false);
86 using tools::Rectangle;
88 static const BmpScaleFlag scaleMethods[]
89 = { BmpScaleFlag::Default, BmpScaleFlag::Fast, BmpScaleFlag::BestQuality,
90 BmpScaleFlag::Interpolate, BmpScaleFlag::Lanczos, BmpScaleFlag::BiCubic,
91 BmpScaleFlag::BiLinear };
92 for (BmpScaleFlag scaleMethod : scaleMethods)
94 struct ScaleSize
96 Size srcSize;
97 Size destSize;
99 static const ScaleSize scaleSizes[]
100 = { // test no-op
101 { Size(16, 16), Size(16, 16) },
102 // powers of 2 (OpenGL may use texture atlas)
103 { Size(16, 16), Size(14, 14) },
104 { Size(14, 14), Size(16, 16) }, // both upscaling and downscaling
105 // "random" sizes
106 { Size(18, 18), Size(14, 14) },
107 { Size(14, 14), Size(18, 18) },
108 // different x/y ratios
109 { Size(16, 30), Size(14, 18) },
110 { Size(14, 18), Size(16, 30) },
111 // ratio larger than 16 (triggers different paths in some OpenGL algorithms)
112 { Size(18 * 20, 18 * 20), Size(14, 14) },
113 { Size(14, 14), Size(18 * 20, 18 * 20) },
114 // Boundary cases.
115 { Size(1, 1), Size(1, 1) },
116 { Size(16, 1), Size(12, 1) },
117 { Size(1, 16), Size(1, 12) }
119 for (const ScaleSize& scaleSize : scaleSizes)
121 OString testStr = "Testing scale (" + scaleSize.srcSize.toString() + ")->("
122 + scaleSize.destSize.toString() + "), method "
123 + OString::number(static_cast<int>(scaleMethod));
124 fprintf(stderr, "%s\n", testStr.getStr());
125 Bitmap bitmap(scaleSize.srcSize, 24);
127 // Fill each quarter of the source bitmap with a different color,
128 // and center with yet another color.
129 BitmapScopedWriteAccess writeAccess(bitmap);
130 const int halfW = scaleSize.srcSize.getWidth() / 2;
131 const int halfH = scaleSize.srcSize.getHeight() / 2;
132 const Size aSize(std::max(halfW, 1), std::max(halfH, 1));
134 writeAccess->SetFillColor(COL_GREEN);
135 writeAccess->FillRect(Rectangle(Point(0, 0), aSize));
136 writeAccess->SetFillColor(COL_RED);
137 writeAccess->FillRect(Rectangle(Point(0, halfH), aSize));
138 writeAccess->SetFillColor(COL_YELLOW);
139 writeAccess->FillRect(Rectangle(Point(halfW, 0), aSize));
140 writeAccess->SetFillColor(COL_BLACK);
141 writeAccess->FillRect(Rectangle(Point(halfW, halfH), aSize));
142 writeAccess->SetFillColor(COL_BLUE);
143 writeAccess->FillRect(Rectangle(Point(halfW / 2, halfH / 2), aSize));
145 if (bExportBitmap)
147 SvFileStream aStream("~/scale_before.png", StreamMode::WRITE | StreamMode::TRUNC);
148 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
149 rFilter.compressAsPNG(BitmapEx(bitmap), aStream);
151 CPPUNIT_ASSERT(bitmap.Scale(scaleSize.destSize, scaleMethod));
152 if (bExportBitmap)
154 SvFileStream aStream("~/scale_after.png", StreamMode::WRITE | StreamMode::TRUNC);
155 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
156 rFilter.compressAsPNG(BitmapEx(bitmap), aStream);
158 CPPUNIT_ASSERT_EQUAL(scaleSize.destSize, bitmap.GetSizePixel());
159 const int lastW = scaleSize.destSize.getWidth() - 1;
160 const int lastH = scaleSize.destSize.getHeight() - 1;
161 if (scaleSize.srcSize.getWidth() == 1 && scaleSize.srcSize.getHeight() == 1)
163 BitmapReadAccess readAccess(bitmap);
164 assertColorsAreSimilar(2, __LINE__, COL_BLUE, readAccess.GetColor(0, 0));
165 assertColorsAreSimilar(2, __LINE__, COL_BLUE, readAccess.GetColor(lastH, 0));
166 assertColorsAreSimilar(2, __LINE__, COL_BLUE, readAccess.GetColor(0, lastW));
167 assertColorsAreSimilar(2, __LINE__, COL_BLUE, readAccess.GetColor(lastH, lastW));
168 assertColorsAreSimilar(2, __LINE__, COL_BLUE,
169 readAccess.GetColor(lastH / 2, lastW / 2));
171 else if (lastW && lastH)
173 // Scaling should keep each quarter of the resulting bitmap have the same color,
174 // so check that color in each corner of the result bitmap is the same color,
175 // or reasonably close (some algorithms may alter the color very slightly).
176 BitmapReadAccess readAccess(bitmap);
177 assertColorsAreSimilar(2, __LINE__, COL_GREEN, readAccess.GetColor(0, 0));
178 assertColorsAreSimilar(2, __LINE__, COL_RED, readAccess.GetColor(lastH, 0));
179 assertColorsAreSimilar(2, __LINE__, COL_YELLOW, readAccess.GetColor(0, lastW));
180 assertColorsAreSimilar(2, __LINE__, COL_BLACK, readAccess.GetColor(lastH, lastW));
181 assertColorsAreSimilar(2, __LINE__, COL_BLUE,
182 readAccess.GetColor(lastH / 2, lastW / 2));
184 else if (lastW)
186 BitmapReadAccess readAccess(bitmap);
187 assertColorsAreSimilar(2, __LINE__, COL_RED, readAccess.GetColor(0, 0));
188 assertColorsAreSimilar(2, __LINE__, COL_BLACK, readAccess.GetColor(0, lastW));
189 assertColorsAreSimilar(2, __LINE__, COL_BLUE, readAccess.GetColor(0, lastW / 2));
191 else if (lastH)
193 BitmapReadAccess readAccess(bitmap);
194 assertColorsAreSimilar(2, __LINE__, COL_YELLOW, readAccess.GetColor(0, 0));
195 assertColorsAreSimilar(2, __LINE__, COL_BLACK, readAccess.GetColor(lastH, 0));
196 assertColorsAreSimilar(2, __LINE__, COL_BLUE, readAccess.GetColor(lastH / 2, 0));
202 void BitmapScaleTest::testScale2()
204 const bool bExportBitmap(false);
206 Bitmap aBitmap24Bit(Size(4096, 4096), 24);
207 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(24), aBitmap24Bit.GetBitCount());
208 Color aBitmapColor = COL_YELLOW;
210 BitmapScopedWriteAccess aWriteAccess(aBitmap24Bit);
211 aWriteAccess->Erase(aBitmapColor);
214 if (bExportBitmap)
216 SvFileStream aStream("scale_before.png", StreamMode::WRITE | StreamMode::TRUNC);
217 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
218 rFilter.compressAsPNG(BitmapEx(aBitmap24Bit), aStream);
221 // Scale - 65x65
222 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(4096), aBitmap24Bit.GetSizePixel().Width());
223 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(4096), aBitmap24Bit.GetSizePixel().Height());
224 Bitmap aScaledBitmap = aBitmap24Bit;
225 aScaledBitmap.Scale(Size(65, 65));
227 if (bExportBitmap)
229 SvFileStream aStream("scale_after_65x65.png", StreamMode::WRITE | StreamMode::TRUNC);
230 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
231 rFilter.compressAsPNG(BitmapEx(aScaledBitmap), aStream);
234 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(65), aScaledBitmap.GetSizePixel().Width());
235 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(65), aScaledBitmap.GetSizePixel().Height());
236 CPPUNIT_ASSERT(checkBitmapColor(aScaledBitmap, aBitmapColor));
238 // Scale - 64x64
239 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(4096), aBitmap24Bit.GetSizePixel().Width());
240 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(4096), aBitmap24Bit.GetSizePixel().Height());
241 aScaledBitmap = aBitmap24Bit;
242 aScaledBitmap.Scale(Size(64, 64));
244 if (bExportBitmap)
246 SvFileStream aStream("scale_after_64x64.png", StreamMode::WRITE | StreamMode::TRUNC);
247 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
248 rFilter.compressAsPNG(BitmapEx(aScaledBitmap), aStream);
251 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(64), aScaledBitmap.GetSizePixel().Width());
252 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(64), aScaledBitmap.GetSizePixel().Height());
253 CPPUNIT_ASSERT(checkBitmapColor(aScaledBitmap, aBitmapColor));
255 // Scale - 63x63
256 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(4096), aBitmap24Bit.GetSizePixel().Width());
257 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(4096), aBitmap24Bit.GetSizePixel().Height());
258 aScaledBitmap = aBitmap24Bit;
259 aScaledBitmap.Scale(Size(63, 63));
261 if (bExportBitmap)
263 SvFileStream aStream("scale_after_63x63.png", StreamMode::WRITE | StreamMode::TRUNC);
264 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
265 rFilter.compressAsPNG(BitmapEx(aScaledBitmap), aStream);
268 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(63), aScaledBitmap.GetSizePixel().Width());
269 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(63), aScaledBitmap.GetSizePixel().Height());
270 CPPUNIT_ASSERT(checkBitmapColor(aScaledBitmap, aBitmapColor));
273 void BitmapScaleTest::testScaleSymmetry()
275 const bool bExportBitmap(false);
277 Bitmap aBitmap24Bit(Size(10, 10), 24);
278 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(24), aBitmap24Bit.GetBitCount());
281 BitmapScopedWriteAccess aWriteAccess(aBitmap24Bit);
282 aWriteAccess->Erase(COL_WHITE);
283 aWriteAccess->SetLineColor(COL_BLACK);
284 aWriteAccess->DrawRect(tools::Rectangle(1, 1, 8, 8));
285 aWriteAccess->DrawRect(tools::Rectangle(3, 3, 6, 6));
288 BitmapSymmetryCheck aBitmapSymmetryCheck;
290 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(10), aBitmap24Bit.GetSizePixel().Width());
291 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(10), aBitmap24Bit.GetSizePixel().Height());
293 // Check symmetry of the bitmap
294 CPPUNIT_ASSERT(BitmapSymmetryCheck::check(aBitmap24Bit));
296 if (bExportBitmap)
298 SvFileStream aStream("~/scale_before.png", StreamMode::WRITE | StreamMode::TRUNC);
299 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
300 rFilter.compressAsPNG(BitmapEx(aBitmap24Bit), aStream);
303 aBitmap24Bit.Scale(2, 2, BmpScaleFlag::Fast);
305 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(20), aBitmap24Bit.GetSizePixel().Width());
306 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(20), aBitmap24Bit.GetSizePixel().Height());
308 // After scaling the bitmap should still be symmetrical. This check guarantees that
309 // scaling doesn't misalign the bitmap.
310 CPPUNIT_ASSERT(BitmapSymmetryCheck::check(aBitmap24Bit));
312 if (bExportBitmap)
314 SvFileStream aStream("~/scale_after.png", StreamMode::WRITE | StreamMode::TRUNC);
315 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
316 rFilter.compressAsPNG(BitmapEx(aBitmap24Bit), aStream);
320 } // namespace
322 CPPUNIT_TEST_SUITE_REGISTRATION(BitmapScaleTest);
324 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */