2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 #include <cppunit/TestAssert.h>
10 #include <cppunit/TestFixture.h>
11 #include <cppunit/extensions/HelperMacros.h>
12 #include <cppunit/plugin/TestPlugIn.h>
14 #include <config_features.h>
16 #include <rtl/strbuf.hxx>
18 #include <vcl/BitmapTools.hxx>
19 #include <vcl/BitmapWriteAccess.hxx>
20 #include <vcl/bitmap/BitmapMonochromeFilter.hxx>
21 #include <vcl/virdev.hxx>
22 #include <vcl/skia/SkiaHelper.hxx>
24 #include <bitmap/Octree.hxx>
25 #include <salinst.hxx>
28 #include <unordered_map>
32 class BitmapTest
: public CppUnit::TestFixture
36 void testMonochrome();
37 void testN8Greyscale();
40 void testGreyPalette();
41 void testCustom8BitPalette();
45 void testEmptyAccess();
46 void testDitherSize();
49 void testCroppedDownsampledBitmap();
51 CPPUNIT_TEST_SUITE(BitmapTest
);
52 CPPUNIT_TEST(testCreation
);
53 CPPUNIT_TEST(testEmpty
);
54 CPPUNIT_TEST(testMonochrome
);
55 CPPUNIT_TEST(testConvert
);
56 CPPUNIT_TEST(testN8Greyscale
);
57 CPPUNIT_TEST(testCRC
);
58 CPPUNIT_TEST(testGreyPalette
);
59 CPPUNIT_TEST(testCustom8BitPalette
);
60 CPPUNIT_TEST(testErase
);
61 CPPUNIT_TEST(testBitmap32
);
62 CPPUNIT_TEST(testOctree
);
63 CPPUNIT_TEST(testEmptyAccess
);
64 CPPUNIT_TEST(testDitherSize
);
65 CPPUNIT_TEST(testMirror
);
66 CPPUNIT_TEST(testCrop
);
67 CPPUNIT_TEST(testCroppedDownsampledBitmap
);
68 CPPUNIT_TEST_SUITE_END();
71 void assertColorsAreSimilar(int maxDifference
, const std::string
& message
,
72 const BitmapColor
& expected
, const BitmapColor
& actual
)
74 // Check that the two colors match or are reasonably similar.
75 if (expected
.GetColorError(actual
) <= maxDifference
)
77 CPPUNIT_ASSERT_EQUAL_MESSAGE(message
, expected
, actual
);
80 void BitmapTest::testCreation()
84 Size aSize
= aBmp
.GetSizePixel();
85 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long
>(0), aSize
.Width());
86 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long
>(0), aSize
.Height());
87 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp
.GetPrefSize());
88 CPPUNIT_ASSERT_MESSAGE("Not empty", aBmp
.IsEmpty());
89 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::INVALID
,
90 aBmp
.getPixelFormat());
91 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_Int64
>(0),
96 Bitmap
aBmp(Size(10, 10), vcl::PixelFormat::N8_BPP
);
97 Size aSize
= aBmp
.GetSizePixel();
98 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long
>(10), aSize
.Width());
99 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long
>(10), aSize
.Height());
100 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp
.GetPrefSize());
101 CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp
.IsEmpty());
102 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::N8_BPP
,
103 aBmp
.getPixelFormat());
104 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_Int64
>(100),
105 aBmp
.GetSizeBytes());
109 Bitmap
aBmp(Size(10, 10), vcl::PixelFormat::N24_BPP
);
110 Size aSize
= aBmp
.GetSizePixel();
111 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long
>(10), aSize
.Width());
112 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long
>(10), aSize
.Height());
113 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp
.GetPrefSize());
114 CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp
.IsEmpty());
115 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::N24_BPP
,
116 aBmp
.getPixelFormat());
117 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_Int64
>(300),
118 aBmp
.GetSizeBytes());
121 // Check backend capabilities and return from the test successfully
122 // if the backend doesn't support 32-bit bitmap
123 if (ImplGetSVData()->mpDefInst
->supportsBitmap32())
125 Bitmap
aBmp(Size(10, 10), vcl::PixelFormat::N32_BPP
);
126 Size aSize
= aBmp
.GetSizePixel();
127 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long
>(10), aSize
.Width());
128 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long
>(10), aSize
.Height());
129 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp
.GetPrefSize());
130 CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp
.IsEmpty());
131 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::N32_BPP
,
132 aBmp
.getPixelFormat());
133 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", sal_Int64(400), aBmp
.GetSizeBytes());
137 void BitmapTest::testEmpty()
139 Bitmap
aBitmap(Size(10, 10), vcl::PixelFormat::N8_BPP
);
140 aBitmap
.Erase(COL_LIGHTGRAYBLUE
);
142 CPPUNIT_ASSERT(!aBitmap
.IsEmpty());
145 CPPUNIT_ASSERT(aBitmap
.IsEmpty());
148 Bitmap
createTestBitmap()
150 Bitmap
aBmp(Size(4, 4), vcl::PixelFormat::N24_BPP
);
151 BitmapWriteAccess
aBmpAccess(aBmp
);
154 aBmpAccess
.SetPixel(0, 0, BitmapColor(COL_BLACK
));
155 aBmpAccess
.SetPixel(0, 1, BitmapColor(COL_BLUE
));
156 aBmpAccess
.SetPixel(0, 2, BitmapColor(COL_GREEN
));
157 aBmpAccess
.SetPixel(0, 3, BitmapColor(COL_CYAN
));
160 aBmpAccess
.SetPixel(1, 0, BitmapColor(COL_RED
));
161 aBmpAccess
.SetPixel(1, 1, BitmapColor(COL_MAGENTA
));
162 aBmpAccess
.SetPixel(1, 2, BitmapColor(COL_BROWN
));
163 aBmpAccess
.SetPixel(1, 3, BitmapColor(COL_GRAY
));
166 aBmpAccess
.SetPixel(2, 0, BitmapColor(COL_LIGHTGRAY
));
167 aBmpAccess
.SetPixel(2, 1, BitmapColor(COL_LIGHTBLUE
));
168 aBmpAccess
.SetPixel(2, 2, BitmapColor(COL_LIGHTGREEN
));
169 aBmpAccess
.SetPixel(2, 3, BitmapColor(COL_LIGHTCYAN
));
172 aBmpAccess
.SetPixel(3, 0, BitmapColor(COL_LIGHTRED
));
173 aBmpAccess
.SetPixel(3, 1, BitmapColor(COL_LIGHTMAGENTA
));
174 aBmpAccess
.SetPixel(3, 2, BitmapColor(COL_YELLOW
));
175 aBmpAccess
.SetPixel(3, 3, BitmapColor(COL_WHITE
));
180 void BitmapTest::testMonochrome()
182 Bitmap aBmp
= createTestBitmap();
184 BitmapEx
aBmpEx(aBmp
);
185 BitmapFilter::Filter(aBmpEx
, BitmapMonochromeFilter(63));
186 aBmp
= aBmpEx
.GetBitmap();
187 BitmapReadAccess
aBmpReadAccess(aBmp
);
189 CPPUNIT_ASSERT_EQUAL_MESSAGE("Black pixel wrong monochrome value", BitmapColor(COL_BLACK
),
190 aBmpReadAccess
.GetColor(0, 0));
191 CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue pixel wrong monochrome value", BitmapColor(COL_BLACK
),
192 aBmpReadAccess
.GetColor(0, 1));
193 CPPUNIT_ASSERT_EQUAL_MESSAGE("Green pixel wrong monochrome value", BitmapColor(COL_WHITE
),
194 aBmpReadAccess
.GetColor(0, 2));
195 CPPUNIT_ASSERT_EQUAL_MESSAGE("Cyan pixel wrong monochrome value", BitmapColor(COL_WHITE
),
196 aBmpReadAccess
.GetColor(0, 3));
197 CPPUNIT_ASSERT_EQUAL_MESSAGE("Red pixel wrong monochrome value", BitmapColor(COL_BLACK
),
198 aBmpReadAccess
.GetColor(1, 0));
199 CPPUNIT_ASSERT_EQUAL_MESSAGE("Magenta pixel wrong monochrome value", BitmapColor(COL_BLACK
),
200 aBmpReadAccess
.GetColor(1, 1));
201 CPPUNIT_ASSERT_EQUAL_MESSAGE("Brown pixel wrong monochrome value", BitmapColor(COL_WHITE
),
202 aBmpReadAccess
.GetColor(1, 2));
203 CPPUNIT_ASSERT_EQUAL_MESSAGE("Gray pixel wrong monochrome value", BitmapColor(COL_WHITE
),
204 aBmpReadAccess
.GetColor(1, 3));
205 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light gray pixel wrong monochrome value", BitmapColor(COL_WHITE
),
206 aBmpReadAccess
.GetColor(2, 0));
207 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light blue pixel wrong monochrome value", BitmapColor(COL_BLACK
),
208 aBmpReadAccess
.GetColor(2, 1));
209 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light green pixel wrong monochrome value", BitmapColor(COL_WHITE
),
210 aBmpReadAccess
.GetColor(2, 2));
211 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light cyan pixel wrong monochrome value", BitmapColor(COL_WHITE
),
212 aBmpReadAccess
.GetColor(2, 3));
213 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light red pixel wrong monochrome value", BitmapColor(COL_WHITE
),
214 aBmpReadAccess
.GetColor(3, 0));
215 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light magenta pixel wrong monochrome value",
216 BitmapColor(COL_WHITE
), aBmpReadAccess
.GetColor(3, 1));
217 CPPUNIT_ASSERT_EQUAL_MESSAGE("Yellow pixel wrong monochrome value", BitmapColor(COL_WHITE
),
218 aBmpReadAccess
.GetColor(3, 2));
219 CPPUNIT_ASSERT_EQUAL_MESSAGE("White pixel wrong monochrome value", BitmapColor(COL_WHITE
),
220 aBmpReadAccess
.GetColor(3, 3));
223 void BitmapTest::testN8Greyscale()
225 Bitmap aBmp
= createTestBitmap();
226 BitmapPalette aGreyscalePalette
= Bitmap::GetGreyPalette(256);
228 aBmp
.Convert(BmpConversion::N8BitGreys
);
229 BitmapReadAccess
aBmpReadAccess(aBmp
);
231 assertColorsAreSimilar(1, "Black pixel wrong 8-bit greyscale value", aGreyscalePalette
[0],
232 aBmpReadAccess
.GetColor(0, 0));
233 assertColorsAreSimilar(1, "Blue pixel wrong 8-bit greyscale value", aGreyscalePalette
[14],
234 aBmpReadAccess
.GetColor(0, 1));
235 assertColorsAreSimilar(1, "Green pixel wrong 8-bit greyscale value", aGreyscalePalette
[75],
236 aBmpReadAccess
.GetColor(0, 2));
237 assertColorsAreSimilar(1, "Cyan pixel wrong 8-bit greyscale value", aGreyscalePalette
[89],
238 aBmpReadAccess
.GetColor(0, 3));
239 assertColorsAreSimilar(1, "Red pixel wrong 8-bit greyscale value", aGreyscalePalette
[38],
240 aBmpReadAccess
.GetColor(1, 0));
241 assertColorsAreSimilar(1, "Magenta pixel wrong 8-bit greyscale value", aGreyscalePalette
[52],
242 aBmpReadAccess
.GetColor(1, 1));
243 assertColorsAreSimilar(1, "Brown pixel wrong 8-bit greyscale value", aGreyscalePalette
[114],
244 aBmpReadAccess
.GetColor(1, 2));
245 assertColorsAreSimilar(1, "Gray pixel wrong 8-bit greyscale value", aGreyscalePalette
[128],
246 aBmpReadAccess
.GetColor(1, 3));
247 assertColorsAreSimilar(1, "Light gray pixel wrong 8-bit greyscale value",
248 aGreyscalePalette
[192], aBmpReadAccess
.GetColor(2, 0));
249 assertColorsAreSimilar(1, "Light blue pixel wrong 8-bit greyscale value", aGreyscalePalette
[27],
250 aBmpReadAccess
.GetColor(2, 1));
251 assertColorsAreSimilar(1, "Light green pixel wrong 8-bit greyscale value",
252 aGreyscalePalette
[150], aBmpReadAccess
.GetColor(2, 2));
253 assertColorsAreSimilar(1, "Light cyan pixel wrong 8-bit greyscale value",
254 aGreyscalePalette
[178], aBmpReadAccess
.GetColor(2, 3));
255 assertColorsAreSimilar(1, "Light red pixel wrong 8-bit greyscale value", aGreyscalePalette
[76],
256 aBmpReadAccess
.GetColor(3, 0));
257 assertColorsAreSimilar(1, "Light magenta pixel wrong 8-bit greyscale value",
258 aGreyscalePalette
[104], aBmpReadAccess
.GetColor(3, 1));
259 assertColorsAreSimilar(1, "Yellow pixel wrong 8-bit greyscale value", aGreyscalePalette
[227],
260 aBmpReadAccess
.GetColor(3, 2));
261 assertColorsAreSimilar(1, "White pixel wrong 8-bit greyscale value", aGreyscalePalette
[255],
262 aBmpReadAccess
.GetColor(3, 3));
265 void BitmapTest::testConvert()
267 Bitmap
aBitmap(Size(10, 10), vcl::PixelFormat::N8_BPP
);
269 aBitmap
.Erase(COL_LIGHTGRAYBLUE
);
271 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP
, aBitmap
.getPixelFormat());
273 BitmapScopedReadAccess
pReadAccess(aBitmap
);
274 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(8), pReadAccess
->GetBitCount());
275 #if defined MACOSX || defined IOS
276 if (SkiaHelper::isVCLSkiaEnabled())
277 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32
>(12), pReadAccess
->GetScanlineSize());
279 //it would be nice to find and change the stride for quartz to be the same as everyone else
280 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32
>(10), pReadAccess
->GetScanlineSize());
282 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32
>(12), pReadAccess
->GetScanlineSize());
284 CPPUNIT_ASSERT(pReadAccess
->HasPalette());
285 const BitmapColor
& rColor
= pReadAccess
->GetPaletteColor(pReadAccess
->GetPixelIndex(1, 1));
286 CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(rColor
.GetRed()));
287 CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(rColor
.GetGreen()));
288 CPPUNIT_ASSERT_EQUAL(sal_Int32(255), sal_Int32(rColor
.GetBlue()));
291 aBitmap
.Convert(BmpConversion::N24Bit
);
293 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP
, aBitmap
.getPixelFormat());
295 BitmapScopedReadAccess
pReadAccess(aBitmap
);
296 // 24 bit Bitmap on SVP backend can now use 24bit RGB everywhere.
297 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(24), pReadAccess
->GetBitCount());
299 if (SkiaHelper::isVCLSkiaEnabled()) // aligned to 4 bytes
300 CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess
->GetScanlineSize());
302 #if defined LINUX || defined FREEBSD
304 CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess
->GetScanlineSize());
306 #elif defined(_WIN32)
308 // GDI Scanlines padded to DWORD multiples, it seems
309 CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess
->GetScanlineSize());
313 CPPUNIT_ASSERT_EQUAL(sal_uInt32(30), pReadAccess
->GetScanlineSize());
317 CPPUNIT_ASSERT(!pReadAccess
->HasPalette());
318 Color aColor
= pReadAccess
->GetPixel(0, 0);
319 CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor
.GetRed()));
320 CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor
.GetGreen()));
321 CPPUNIT_ASSERT_EQUAL(sal_Int32(255), sal_Int32(aColor
.GetBlue()));
325 typedef std::unordered_map
<sal_uInt64
, const char*> CRCHash
;
327 void checkAndInsert(CRCHash
& rHash
, sal_uInt64 nCRC
, const char* pLocation
)
329 auto it
= rHash
.find(nCRC
);
330 if (it
!= rHash
.end())
332 OString aBuf
= OString::Concat("CRC collision between ") + pLocation
+ " and " + it
->second
333 + " hash is 0x" + OString::number(static_cast<sal_Int64
>(nCRC
), 16);
334 CPPUNIT_FAIL(aBuf
.getStr());
336 rHash
[nCRC
] = pLocation
;
339 void checkAndInsert(CRCHash
& rHash
, Bitmap
const& rBmp
, const char* pLocation
)
341 checkAndInsert(rHash
, rBmp
.GetChecksum(), pLocation
);
344 Bitmap
getAsBitmap(VclPtr
<OutputDevice
> const& pOut
)
346 return pOut
->GetBitmap(Point(), pOut
->GetOutputSizePixel());
349 void BitmapTest::testCRC()
353 Bitmap
aBitmap(Size(1023, 759), vcl::PixelFormat::N24_BPP
);
354 aBitmap
.Erase(COL_BLACK
);
355 checkAndInsert(aCRCs
, aBitmap
, "black bitmap");
357 checkAndInsert(aCRCs
, aBitmap
, "white bitmap");
359 ScopedVclPtrInstance
<VirtualDevice
> aVDev
;
360 aVDev
->SetBackground(Wallpaper(COL_WHITE
));
361 aVDev
->SetOutputSizePixel(Size(1023, 759));
363 #if 0 // disabled for now - oddly breaks on OS/X - but why ?
364 Bitmap aWhiteCheck
= getAsBitmap(aVDev
);
365 CPPUNIT_ASSERT(aCRCs
.find(aWhiteCheck
.GetChecksum()) != aCRCs
.end());
368 // a 1x1 black & white checkerboard
369 aVDev
->DrawCheckered(Point(), aVDev
->GetOutputSizePixel(), 1, Color(0, 0, 1));
370 Bitmap aChecker
= getAsBitmap(aVDev
);
371 checkAndInsert(aCRCs
, aChecker
, "checkerboard");
373 checkAndInsert(aCRCs
, aChecker
, "inverted checkerboard");
376 void BitmapTest::testGreyPalette()
379 BitmapPalette aPalette
= Bitmap::GetGreyPalette(2);
380 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16
>(2),
381 aPalette
.GetEntryCount());
382 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette
[0]);
383 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(255, 255, 255), aPalette
[1]);
387 BitmapPalette aPalette
= Bitmap::GetGreyPalette(4);
388 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16
>(4),
389 aPalette
.GetEntryCount());
390 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette
[0]);
391 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(85, 85, 85), aPalette
[1]);
392 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 3 wrong", BitmapColor(170, 170, 170), aPalette
[2]);
393 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 4 wrong", BitmapColor(255, 255, 255), aPalette
[3]);
397 BitmapPalette aPalette
= Bitmap::GetGreyPalette(16);
398 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16
>(16),
399 aPalette
.GetEntryCount());
400 // this is a *real* specific number of greys, incremented in units of 17 so may
401 // as well test them all...
402 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette
[0]);
403 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(17, 17, 17), aPalette
[1]);
404 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 3 wrong", BitmapColor(34, 34, 34), aPalette
[2]);
405 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 4 wrong", BitmapColor(51, 51, 51), aPalette
[3]);
406 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 5 wrong", BitmapColor(68, 68, 68), aPalette
[4]);
407 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 6 wrong", BitmapColor(85, 85, 85), aPalette
[5]);
408 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 7 wrong", BitmapColor(102, 102, 102), aPalette
[6]);
409 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 8 wrong", BitmapColor(119, 119, 119), aPalette
[7]);
410 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 9 wrong", BitmapColor(136, 136, 136), aPalette
[8]);
411 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 10 wrong", BitmapColor(153, 153, 153), aPalette
[9]);
412 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 11 wrong", BitmapColor(170, 170, 170), aPalette
[10]);
413 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 12 wrong", BitmapColor(187, 187, 187), aPalette
[11]);
414 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 13 wrong", BitmapColor(204, 204, 204), aPalette
[12]);
415 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 14 wrong", BitmapColor(221, 221, 221), aPalette
[13]);
416 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 15 wrong", BitmapColor(238, 238, 238), aPalette
[14]);
417 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 16 wrong", BitmapColor(255, 255, 255), aPalette
[15]);
421 BitmapPalette aPalette
= Bitmap::GetGreyPalette(256);
422 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries",
423 static_cast<sal_uInt16
>(256), aPalette
.GetEntryCount());
424 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette
[0]);
425 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 127 wrong", BitmapColor(127, 127, 127), aPalette
[127]);
426 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 255 wrong", BitmapColor(255, 255, 255), aPalette
[255]);
430 void BitmapTest::testCustom8BitPalette()
432 BitmapPalette aCustomPalette
;
433 aCustomPalette
.SetEntryCount(256);
434 for (sal_uInt16 i
= 0; i
< 256; i
++)
436 aCustomPalette
[i
] = BitmapColor(sal_uInt8(i
), sal_uInt8(0xCC), sal_uInt8(0x22));
438 Bitmap
aBitmap(Size(3, 2), vcl::PixelFormat::N8_BPP
, &aCustomPalette
);
441 BitmapScopedWriteAccess
pAccess(aBitmap
);
442 pAccess
->SetPixelIndex(0, 0, 0);
443 pAccess
->SetPixelIndex(0, 1, 1);
444 pAccess
->SetPixelIndex(0, 2, 2);
446 pAccess
->SetPixelIndex(1, 0, 253);
447 pAccess
->SetPixelIndex(1, 1, 254);
448 pAccess
->SetPixelIndex(1, 2, 255);
452 BitmapScopedReadAccess
pAccess(aBitmap
);
453 CPPUNIT_ASSERT_EQUAL(0, int(pAccess
->GetPixelIndex(0, 0)));
454 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xCC, 0x22), pAccess
->GetColor(0, 0));
456 CPPUNIT_ASSERT_EQUAL(1, int(pAccess
->GetPixelIndex(0, 1)));
457 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x01, 0xCC, 0x22), pAccess
->GetColor(0, 1));
459 CPPUNIT_ASSERT_EQUAL(2, int(pAccess
->GetPixelIndex(0, 2)));
460 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x02, 0xCC, 0x22), pAccess
->GetColor(0, 2));
462 CPPUNIT_ASSERT_EQUAL(253, int(pAccess
->GetPixelIndex(1, 0)));
463 CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFD, 0xCC, 0x22), pAccess
->GetColor(1, 0));
465 CPPUNIT_ASSERT_EQUAL(254, int(pAccess
->GetPixelIndex(1, 1)));
466 CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFE, 0xCC, 0x22), pAccess
->GetColor(1, 1));
468 CPPUNIT_ASSERT_EQUAL(255, int(pAccess
->GetPixelIndex(1, 2)));
469 CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xCC, 0x22), pAccess
->GetColor(1, 2));
473 void BitmapTest::testErase()
475 Bitmap
aBitmap(Size(3, 3), vcl::PixelFormat::N24_BPP
);
477 BitmapScopedWriteAccess
pWriteAccess(aBitmap
);
478 pWriteAccess
->Erase(Color(0x11, 0x22, 0x33));
481 BitmapScopedReadAccess
pReadAccess(aBitmap
);
482 BitmapColor
aColor(pReadAccess
->GetPixel(0, 0));
483 CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency
, 0x11, 0x22, 0x33, 0x00), aColor
);
487 void BitmapTest::testBitmap32()
489 // Check backend capabilities and return from the test successfully
490 // if the backend doesn't support 32-bit bitmap
491 if (!ImplGetSVData()->mpDefInst
->supportsBitmap32())
494 Bitmap
aBitmap(Size(3, 3), vcl::PixelFormat::N32_BPP
);
496 BitmapScopedWriteAccess
pWriteAccess(aBitmap
);
497 pWriteAccess
->Erase(Color(ColorTransparency
, 0xFF, 0x11, 0x22, 0x33));
498 pWriteAccess
->SetPixel(1, 1, BitmapColor(ColorTransparency
, 0x44, 0xFF, 0xBB, 0x00));
499 pWriteAccess
->SetPixel(2, 2, BitmapColor(ColorTransparency
, 0x99, 0x77, 0x66, 0x55));
502 BitmapScopedReadAccess
pReadAccess(aBitmap
);
503 BitmapColor aColor
= pReadAccess
->GetPixel(0, 0);
504 CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency
, 0x00, 0x00, 0x00, 0xFF), aColor
);
506 aColor
= pReadAccess
->GetPixel(1, 1);
507 CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency
, 0x44, 0xFF, 0xBB, 0x00), aColor
);
509 aColor
= pReadAccess
->GetPixel(2, 2);
510 CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency
, 0x99, 0x77, 0x66, 0x55), aColor
);
514 void BitmapTest::testOctree()
516 Size
aSize(1000, 100);
517 Bitmap
aBitmap(aSize
, vcl::PixelFormat::N24_BPP
);
519 BitmapScopedWriteAccess
pWriteAccess(aBitmap
);
520 for (tools::Long y
= 0; y
< aSize
.Height(); ++y
)
522 for (tools::Long x
= 0; x
< aSize
.Width(); ++x
)
524 double fPercent
= double(x
) / double(aSize
.Width());
525 pWriteAccess
->SetPixel(y
, x
,
526 BitmapColor(255.0 * fPercent
, 64.0 + (128.0 * fPercent
),
527 255.0 - 255.0 * fPercent
));
534 BitmapScopedReadAccess
pAccess(aBitmap
);
535 Octree
aOctree(*pAccess
, 1);
536 auto aBitmapPalette
= aOctree
.GetPalette();
537 CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), aBitmapPalette
.GetEntryCount());
538 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7e, 0x7f, 0x7f), aBitmapPalette
[0]);
543 BitmapScopedReadAccess
pAccess(aBitmap
);
544 Octree
aOctree(*pAccess
, 4);
545 auto aBitmapPalette
= aOctree
.GetPalette();
546 CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), aBitmapPalette
.GetEntryCount());
547 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7f, 0x7f, 0x7f), aBitmapPalette
[0]);
548 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x3e, 0x5f, 0xbf), aBitmapPalette
[1]);
549 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7f, 0x80, 0x7f), aBitmapPalette
[2]);
550 CPPUNIT_ASSERT_EQUAL(BitmapColor(0xbe, 0x9f, 0x3f), aBitmapPalette
[3]);
554 // Reduce to 256 color
555 BitmapScopedReadAccess
pAccess(aBitmap
);
556 Octree
aOctree(*pAccess
, 256);
557 auto aBitmapPalette
= aOctree
.GetPalette();
558 CPPUNIT_ASSERT_EQUAL(sal_uInt16(74), aBitmapPalette
.GetEntryCount());
562 void BitmapTest::testEmptyAccess()
565 BitmapInfoAccess
access(empty
);
566 CPPUNIT_ASSERT_EQUAL(tools::Long(0), access
.Width());
567 CPPUNIT_ASSERT_EQUAL(tools::Long(0), access
.Height());
570 void BitmapTest::testDitherSize()
572 // no need to do anything for a 1x1 pixel bitmap
574 Bitmap
aBitmap(Size(1, 1), vcl::PixelFormat::N24_BPP
);
575 CPPUNIT_ASSERT(aBitmap
.Dither());
578 // cannot dither a bitmap with a width of 2 or 3 pixels
580 Bitmap
aBitmap(Size(2, 4), vcl::PixelFormat::N24_BPP
);
581 CPPUNIT_ASSERT(!aBitmap
.Dither());
585 Bitmap
aBitmap(Size(3, 4), vcl::PixelFormat::N24_BPP
);
586 CPPUNIT_ASSERT(!aBitmap
.Dither());
589 // cannot dither a bitmap with a height of 2 pixels
591 Bitmap
aBitmap(Size(4, 2), vcl::PixelFormat::N24_BPP
);
592 CPPUNIT_ASSERT(!aBitmap
.Dither());
595 // only dither bitmaps with a width > 3 pixels and height > 2 pixels
597 Bitmap
aBitmap(Size(4, 3), vcl::PixelFormat::N24_BPP
);
598 CPPUNIT_ASSERT(aBitmap
.Dither());
602 void BitmapTest::testMirror()
604 vcl::PixelFormat bppArray
[]
605 = { vcl::PixelFormat::N8_BPP
, vcl::PixelFormat::N24_BPP
, vcl::PixelFormat::N32_BPP
};
607 for (vcl::PixelFormat bpp
: bppArray
)
609 Bitmap
bitmap(Size(11, 11), bpp
);
611 bitmap
.Erase(COL_MAGENTA
);
612 BitmapWriteAccess
write(bitmap
);
613 if (write
.HasPalette())
615 // Note that SetPixel() and GetColor() take arguments as Y,X.
616 write
.SetPixel(0, 0, BitmapColor(write
.GetBestPaletteIndex(COL_BLACK
)));
617 write
.SetPixel(10, 0, BitmapColor(write
.GetBestPaletteIndex(COL_WHITE
)));
618 write
.SetPixel(0, 10, BitmapColor(write
.GetBestPaletteIndex(COL_RED
)));
619 write
.SetPixel(10, 10, BitmapColor(write
.GetBestPaletteIndex(COL_BLUE
)));
620 write
.SetPixel(5, 0, BitmapColor(write
.GetBestPaletteIndex(COL_GREEN
)));
621 write
.SetPixel(0, 5, BitmapColor(write
.GetBestPaletteIndex(COL_YELLOW
)));
625 write
.SetPixel(0, 0, COL_BLACK
);
626 write
.SetPixel(10, 0, COL_WHITE
);
627 write
.SetPixel(0, 10, COL_RED
);
628 write
.SetPixel(10, 10, COL_BLUE
);
629 write
.SetPixel(5, 0, COL_GREEN
);
630 write
.SetPixel(0, 5, COL_YELLOW
);
633 bitmap
.Mirror(BmpMirrorFlags::Horizontal
);
635 BitmapReadAccess
read(bitmap
);
636 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK
), read
.GetColor(0, 10));
637 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE
), read
.GetColor(10, 10));
638 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED
), read
.GetColor(0, 0));
639 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE
), read
.GetColor(10, 0));
640 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN
), read
.GetColor(5, 10));
641 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW
), read
.GetColor(0, 5));
643 bitmap
.Mirror(BmpMirrorFlags::Vertical
);
645 BitmapReadAccess
read(bitmap
);
646 // Now is effectively mirrored in both directions.
647 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK
), read
.GetColor(10, 10));
648 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE
), read
.GetColor(0, 10));
649 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED
), read
.GetColor(10, 0));
650 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE
), read
.GetColor(0, 0));
651 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN
), read
.GetColor(5, 10));
652 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW
), read
.GetColor(10, 5));
654 bitmap
.Mirror(BmpMirrorFlags::Vertical
| BmpMirrorFlags::Horizontal
);
656 BitmapReadAccess
read(bitmap
);
657 // Now is back the original.
658 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK
), read
.GetColor(0, 0));
659 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE
), read
.GetColor(10, 0));
660 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED
), read
.GetColor(0, 10));
661 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE
), read
.GetColor(10, 10));
662 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN
), read
.GetColor(5, 0));
663 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW
), read
.GetColor(0, 5));
668 void BitmapTest::testCroppedDownsampledBitmap()
670 Bitmap
aBitmap(Size(16, 16), vcl::PixelFormat::N24_BPP
);
671 Bitmap
aDownsampledBmp(vcl::bitmap::GetDownsampledBitmap(Size(10, 10), Point(20, 20),
672 Size(5, 5), aBitmap
, 72, 72));
673 CPPUNIT_ASSERT(aDownsampledBmp
.IsEmpty());
676 void BitmapTest::testCrop()
678 Bitmap
aBitmap(Bitmap(Size(16, 16), vcl::PixelFormat::N24_BPP
));
681 Bitmap
aCroppedBmp(aBitmap
);
682 CPPUNIT_ASSERT_MESSAGE("Crop was fully outside of bitmap bounds",
683 !aCroppedBmp
.Crop(tools::Rectangle(Point(20, 20), Size(5, 5))));
684 CPPUNIT_ASSERT_EQUAL(Size(16, 16), aCroppedBmp
.GetSizePixel());
688 Bitmap
aCroppedBmp(aBitmap
);
689 CPPUNIT_ASSERT_MESSAGE("Crop same size as bitmap",
690 !aCroppedBmp
.Crop(tools::Rectangle(Point(0, 0), Size(16, 16))));
691 CPPUNIT_ASSERT_EQUAL(Size(16, 16), aCroppedBmp
.GetSizePixel());
695 Bitmap
aCroppedBmp(aBitmap
);
696 CPPUNIT_ASSERT_MESSAGE("Crop larger than bitmap",
697 !aCroppedBmp
.Crop(tools::Rectangle(Point(0, 0), Size(100, 100))));
698 CPPUNIT_ASSERT_EQUAL(Size(16, 16), aCroppedBmp
.GetSizePixel());
702 Bitmap
aCroppedBmp(aBitmap
);
703 CPPUNIT_ASSERT_MESSAGE("Crop partially overcrops bitmap",
704 aCroppedBmp
.Crop(tools::Rectangle(Point(10, 10), Size(100, 100))));
705 CPPUNIT_ASSERT_EQUAL(Size(6, 6), aCroppedBmp
.GetSizePixel());
709 Bitmap
aCroppedBmp(aBitmap
);
710 CPPUNIT_ASSERT_MESSAGE("Crop inside bitmap",
711 aCroppedBmp
.Crop(tools::Rectangle(Point(5, 5), Size(10, 10))));
712 CPPUNIT_ASSERT_EQUAL(Size(10, 10), aCroppedBmp
.GetSizePixel());
717 CPPUNIT_TEST_SUITE_REGISTRATION(BitmapTest
);
719 CPPUNIT_PLUGIN_IMPLEMENT();
721 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */