1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
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>
25 class BitmapScaleTest
: public CppUnit::TestFixture
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
)
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
)
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
)
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
)
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
)
99 static const ScaleSize scaleSizes
[]
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
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) },
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
));
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
));
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));
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));
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
);
216 SvFileStream
aStream("scale_before.png", StreamMode::WRITE
| StreamMode::TRUNC
);
217 GraphicFilter
& rFilter
= GraphicFilter::GetGraphicFilter();
218 rFilter
.compressAsPNG(BitmapEx(aBitmap24Bit
), aStream
);
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));
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
));
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));
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
));
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));
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
));
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
));
314 SvFileStream
aStream("~/scale_after.png", StreamMode::WRITE
| StreamMode::TRUNC
);
315 GraphicFilter
& rFilter
= GraphicFilter::GetGraphicFilter();
316 rFilter
.compressAsPNG(BitmapEx(aBitmap24Bit
), aStream
);
322 CPPUNIT_TEST_SUITE_REGISTRATION(BitmapScaleTest
);
324 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */