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/bitmap.hxx>
20 #include <vcl/virdev.hxx>
21 #include <vcl/skia/SkiaHelper.hxx>
22 #include <vcl/BitmapMonochromeFilter.hxx>
24 #include <bitmap/BitmapWriteAccess.hxx>
25 #include <bitmap/Octree.hxx>
26 #include <salinst.hxx>
29 #include <unordered_map>
33 class BitmapTest
: public CppUnit::TestFixture
37 void testMonochrome();
38 void testN8Greyscale();
41 void testGreyPalette();
42 void testCustom8BitPalette();
46 void testEmptyAccess();
47 void testDitherSize();
50 void testCroppedDownsampledBitmap();
52 CPPUNIT_TEST_SUITE(BitmapTest
);
53 CPPUNIT_TEST(testCreation
);
54 CPPUNIT_TEST(testEmpty
);
55 CPPUNIT_TEST(testMonochrome
);
56 CPPUNIT_TEST(testConvert
);
57 CPPUNIT_TEST(testN8Greyscale
);
58 CPPUNIT_TEST(testCRC
);
59 CPPUNIT_TEST(testGreyPalette
);
60 CPPUNIT_TEST(testCustom8BitPalette
);
61 CPPUNIT_TEST(testErase
);
62 CPPUNIT_TEST(testBitmap32
);
63 CPPUNIT_TEST(testOctree
);
64 CPPUNIT_TEST(testEmptyAccess
);
65 CPPUNIT_TEST(testDitherSize
);
66 CPPUNIT_TEST(testMirror
);
67 CPPUNIT_TEST(testCrop
);
68 CPPUNIT_TEST(testCroppedDownsampledBitmap
);
69 CPPUNIT_TEST_SUITE_END();
72 void assertColorsAreSimilar(int maxDifference
, const std::string
& message
,
73 const BitmapColor
& expected
, const BitmapColor
& actual
)
75 // Check that the two colors match or are reasonably similar.
76 if (expected
.GetColorError(actual
) <= maxDifference
)
78 CPPUNIT_ASSERT_EQUAL_MESSAGE(message
, expected
, actual
);
81 void BitmapTest::testCreation()
85 Size aSize
= aBmp
.GetSizePixel();
86 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long
>(0), aSize
.Width());
87 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long
>(0), aSize
.Height());
88 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp
.GetPrefSize());
89 CPPUNIT_ASSERT_MESSAGE("Not empty", aBmp
.IsEmpty());
90 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::INVALID
,
91 aBmp
.getPixelFormat());
92 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_Int64
>(0),
97 Bitmap
aBmp(Size(10, 10), vcl::PixelFormat::N1_BPP
);
98 Size aSize
= aBmp
.GetSizePixel();
99 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long
>(10), aSize
.Width());
100 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long
>(10), aSize
.Height());
101 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp
.GetPrefSize());
102 CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp
.IsEmpty());
103 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::N1_BPP
,
104 aBmp
.getPixelFormat());
105 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_Int64
>(12),
106 aBmp
.GetSizeBytes());
110 Bitmap
aBmp(Size(10, 10), vcl::PixelFormat::N8_BPP
);
111 Size aSize
= aBmp
.GetSizePixel();
112 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long
>(10), aSize
.Width());
113 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long
>(10), aSize
.Height());
114 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp
.GetPrefSize());
115 CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp
.IsEmpty());
116 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::N8_BPP
,
117 aBmp
.getPixelFormat());
118 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_Int64
>(100),
119 aBmp
.GetSizeBytes());
123 Bitmap
aBmp(Size(10, 10), vcl::PixelFormat::N24_BPP
);
124 Size aSize
= aBmp
.GetSizePixel();
125 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long
>(10), aSize
.Width());
126 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long
>(10), aSize
.Height());
127 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp
.GetPrefSize());
128 CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp
.IsEmpty());
129 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::N24_BPP
,
130 aBmp
.getPixelFormat());
131 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_Int64
>(300),
132 aBmp
.GetSizeBytes());
135 // Check backend capabilities and return from the test successfully
136 // if the backend doesn't support 32-bit bitmap
137 if (ImplGetSVData()->mpDefInst
->supportsBitmap32())
139 Bitmap
aBmp(Size(10, 10), vcl::PixelFormat::N32_BPP
);
140 Size aSize
= aBmp
.GetSizePixel();
141 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long
>(10), aSize
.Width());
142 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long
>(10), aSize
.Height());
143 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp
.GetPrefSize());
144 CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp
.IsEmpty());
145 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::N32_BPP
,
146 aBmp
.getPixelFormat());
147 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", sal_Int64(400), aBmp
.GetSizeBytes());
151 void BitmapTest::testEmpty()
153 Bitmap
aBitmap(Size(10, 10), vcl::PixelFormat::N8_BPP
);
154 aBitmap
.Erase(COL_LIGHTGRAYBLUE
);
156 CPPUNIT_ASSERT(!aBitmap
.IsEmpty());
159 CPPUNIT_ASSERT(aBitmap
.IsEmpty());
162 Bitmap
createTestBitmap()
164 Bitmap
aBmp(Size(4, 4), vcl::PixelFormat::N24_BPP
);
165 BitmapWriteAccess
aBmpAccess(aBmp
);
168 aBmpAccess
.SetPixel(0, 0, BitmapColor(COL_BLACK
));
169 aBmpAccess
.SetPixel(0, 1, BitmapColor(COL_BLUE
));
170 aBmpAccess
.SetPixel(0, 2, BitmapColor(COL_GREEN
));
171 aBmpAccess
.SetPixel(0, 3, BitmapColor(COL_CYAN
));
174 aBmpAccess
.SetPixel(1, 0, BitmapColor(COL_RED
));
175 aBmpAccess
.SetPixel(1, 1, BitmapColor(COL_MAGENTA
));
176 aBmpAccess
.SetPixel(1, 2, BitmapColor(COL_BROWN
));
177 aBmpAccess
.SetPixel(1, 3, BitmapColor(COL_GRAY
));
180 aBmpAccess
.SetPixel(2, 0, BitmapColor(COL_LIGHTGRAY
));
181 aBmpAccess
.SetPixel(2, 1, BitmapColor(COL_LIGHTBLUE
));
182 aBmpAccess
.SetPixel(2, 2, BitmapColor(COL_LIGHTGREEN
));
183 aBmpAccess
.SetPixel(2, 3, BitmapColor(COL_LIGHTCYAN
));
186 aBmpAccess
.SetPixel(3, 0, BitmapColor(COL_LIGHTRED
));
187 aBmpAccess
.SetPixel(3, 1, BitmapColor(COL_LIGHTMAGENTA
));
188 aBmpAccess
.SetPixel(3, 2, BitmapColor(COL_YELLOW
));
189 aBmpAccess
.SetPixel(3, 3, BitmapColor(COL_WHITE
));
194 void BitmapTest::testMonochrome()
196 Bitmap aBmp
= createTestBitmap();
198 BitmapEx
aBmpEx(aBmp
);
199 BitmapFilter::Filter(aBmpEx
, BitmapMonochromeFilter(63));
200 aBmp
= aBmpEx
.GetBitmap();
201 BitmapReadAccess
aBmpReadAccess(aBmp
);
203 CPPUNIT_ASSERT_EQUAL_MESSAGE("Black pixel wrong monochrome value", BitmapColor(COL_BLACK
),
204 aBmpReadAccess
.GetColor(0, 0));
205 CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue pixel wrong monochrome value", BitmapColor(COL_BLACK
),
206 aBmpReadAccess
.GetColor(0, 1));
207 CPPUNIT_ASSERT_EQUAL_MESSAGE("Green pixel wrong monochrome value", BitmapColor(COL_WHITE
),
208 aBmpReadAccess
.GetColor(0, 2));
209 CPPUNIT_ASSERT_EQUAL_MESSAGE("Cyan pixel wrong monochrome value", BitmapColor(COL_WHITE
),
210 aBmpReadAccess
.GetColor(0, 3));
211 CPPUNIT_ASSERT_EQUAL_MESSAGE("Red pixel wrong monochrome value", BitmapColor(COL_BLACK
),
212 aBmpReadAccess
.GetColor(1, 0));
213 CPPUNIT_ASSERT_EQUAL_MESSAGE("Magenta pixel wrong monochrome value", BitmapColor(COL_BLACK
),
214 aBmpReadAccess
.GetColor(1, 1));
215 CPPUNIT_ASSERT_EQUAL_MESSAGE("Brown pixel wrong monochrome value", BitmapColor(COL_WHITE
),
216 aBmpReadAccess
.GetColor(1, 2));
217 CPPUNIT_ASSERT_EQUAL_MESSAGE("Gray pixel wrong monochrome value", BitmapColor(COL_WHITE
),
218 aBmpReadAccess
.GetColor(1, 3));
219 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light gray pixel wrong monochrome value", BitmapColor(COL_WHITE
),
220 aBmpReadAccess
.GetColor(2, 0));
221 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light blue pixel wrong monochrome value", BitmapColor(COL_BLACK
),
222 aBmpReadAccess
.GetColor(2, 1));
223 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light green pixel wrong monochrome value", BitmapColor(COL_WHITE
),
224 aBmpReadAccess
.GetColor(2, 2));
225 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light cyan pixel wrong monochrome value", BitmapColor(COL_WHITE
),
226 aBmpReadAccess
.GetColor(2, 3));
227 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light red pixel wrong monochrome value", BitmapColor(COL_WHITE
),
228 aBmpReadAccess
.GetColor(3, 0));
229 CPPUNIT_ASSERT_EQUAL_MESSAGE("Light magenta pixel wrong monochrome value",
230 BitmapColor(COL_WHITE
), aBmpReadAccess
.GetColor(3, 1));
231 CPPUNIT_ASSERT_EQUAL_MESSAGE("Yellow pixel wrong monochrome value", BitmapColor(COL_WHITE
),
232 aBmpReadAccess
.GetColor(3, 2));
233 CPPUNIT_ASSERT_EQUAL_MESSAGE("White pixel wrong monochrome value", BitmapColor(COL_WHITE
),
234 aBmpReadAccess
.GetColor(3, 3));
237 void BitmapTest::testN8Greyscale()
239 Bitmap aBmp
= createTestBitmap();
240 BitmapPalette aGreyscalePalette
= Bitmap::GetGreyPalette(256);
242 aBmp
.Convert(BmpConversion::N8BitGreys
);
243 BitmapReadAccess
aBmpReadAccess(aBmp
);
245 assertColorsAreSimilar(1, "Black pixel wrong 8-bit greyscale value", aGreyscalePalette
[0],
246 aBmpReadAccess
.GetColor(0, 0));
247 assertColorsAreSimilar(1, "Blue pixel wrong 8-bit greyscale value", aGreyscalePalette
[14],
248 aBmpReadAccess
.GetColor(0, 1));
249 assertColorsAreSimilar(1, "Green pixel wrong 8-bit greyscale value", aGreyscalePalette
[75],
250 aBmpReadAccess
.GetColor(0, 2));
251 assertColorsAreSimilar(1, "Cyan pixel wrong 8-bit greyscale value", aGreyscalePalette
[89],
252 aBmpReadAccess
.GetColor(0, 3));
253 assertColorsAreSimilar(1, "Red pixel wrong 8-bit greyscale value", aGreyscalePalette
[38],
254 aBmpReadAccess
.GetColor(1, 0));
255 assertColorsAreSimilar(1, "Magenta pixel wrong 8-bit greyscale value", aGreyscalePalette
[52],
256 aBmpReadAccess
.GetColor(1, 1));
257 assertColorsAreSimilar(1, "Brown pixel wrong 8-bit greyscale value", aGreyscalePalette
[114],
258 aBmpReadAccess
.GetColor(1, 2));
259 assertColorsAreSimilar(1, "Gray pixel wrong 8-bit greyscale value", aGreyscalePalette
[128],
260 aBmpReadAccess
.GetColor(1, 3));
261 assertColorsAreSimilar(1, "Light gray pixel wrong 8-bit greyscale value",
262 aGreyscalePalette
[192], aBmpReadAccess
.GetColor(2, 0));
263 assertColorsAreSimilar(1, "Light blue pixel wrong 8-bit greyscale value", aGreyscalePalette
[27],
264 aBmpReadAccess
.GetColor(2, 1));
265 assertColorsAreSimilar(1, "Light green pixel wrong 8-bit greyscale value",
266 aGreyscalePalette
[150], aBmpReadAccess
.GetColor(2, 2));
267 assertColorsAreSimilar(1, "Light cyan pixel wrong 8-bit greyscale value",
268 aGreyscalePalette
[178], aBmpReadAccess
.GetColor(2, 3));
269 assertColorsAreSimilar(1, "Light red pixel wrong 8-bit greyscale value", aGreyscalePalette
[76],
270 aBmpReadAccess
.GetColor(3, 0));
271 assertColorsAreSimilar(1, "Light magenta pixel wrong 8-bit greyscale value",
272 aGreyscalePalette
[104], aBmpReadAccess
.GetColor(3, 1));
273 assertColorsAreSimilar(1, "Yellow pixel wrong 8-bit greyscale value", aGreyscalePalette
[227],
274 aBmpReadAccess
.GetColor(3, 2));
275 assertColorsAreSimilar(1, "White pixel wrong 8-bit greyscale value", aGreyscalePalette
[255],
276 aBmpReadAccess
.GetColor(3, 3));
279 void BitmapTest::testConvert()
281 Bitmap
aBitmap(Size(10, 10), vcl::PixelFormat::N8_BPP
);
283 aBitmap
.Erase(COL_LIGHTGRAYBLUE
);
285 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP
, aBitmap
.getPixelFormat());
287 Bitmap::ScopedReadAccess
pReadAccess(aBitmap
);
288 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(8), pReadAccess
->GetBitCount());
289 #if defined MACOSX || defined IOS
290 if (SkiaHelper::isVCLSkiaEnabled())
291 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32
>(12), pReadAccess
->GetScanlineSize());
293 //it would be nice to find and change the stride for quartz to be the same as everyone else
294 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32
>(10), pReadAccess
->GetScanlineSize());
296 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32
>(12), pReadAccess
->GetScanlineSize());
298 CPPUNIT_ASSERT(pReadAccess
->HasPalette());
299 const BitmapColor
& rColor
= pReadAccess
->GetPaletteColor(pReadAccess
->GetPixelIndex(1, 1));
300 CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(rColor
.GetRed()));
301 CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(rColor
.GetGreen()));
302 CPPUNIT_ASSERT_EQUAL(sal_Int32(255), sal_Int32(rColor
.GetBlue()));
305 aBitmap
.Convert(BmpConversion::N24Bit
);
307 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP
, aBitmap
.getPixelFormat());
309 Bitmap::ScopedReadAccess
pReadAccess(aBitmap
);
310 // 24 bit Bitmap on SVP backend can now use 24bit RGB everywhere.
311 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(24), pReadAccess
->GetBitCount());
313 if (SkiaHelper::isVCLSkiaEnabled()) // aligned to 4 bytes
314 CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess
->GetScanlineSize());
316 #if defined LINUX || defined FREEBSD
318 CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess
->GetScanlineSize());
320 #elif defined(_WIN32)
322 // GDI Scanlines padded to DWORD multiples, it seems
323 CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess
->GetScanlineSize());
327 CPPUNIT_ASSERT_EQUAL(sal_uInt32(30), pReadAccess
->GetScanlineSize());
331 CPPUNIT_ASSERT(!pReadAccess
->HasPalette());
332 Color aColor
= pReadAccess
->GetPixel(0, 0);
333 CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor
.GetRed()));
334 CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor
.GetGreen()));
335 CPPUNIT_ASSERT_EQUAL(sal_Int32(255), sal_Int32(aColor
.GetBlue()));
339 typedef std::unordered_map
<sal_uInt64
, const char*> CRCHash
;
341 void checkAndInsert(CRCHash
& rHash
, sal_uInt64 nCRC
, const char* pLocation
)
343 auto it
= rHash
.find(nCRC
);
344 if (it
!= rHash
.end())
346 OStringBuffer
aBuf("CRC collision between ");
347 aBuf
.append(pLocation
);
348 aBuf
.append(" and ");
349 aBuf
.append(it
->second
);
350 aBuf
.append(" hash is 0x");
351 aBuf
.append(static_cast<sal_Int64
>(nCRC
), 16);
352 CPPUNIT_FAIL(aBuf
.toString().getStr());
354 rHash
[nCRC
] = pLocation
;
357 void checkAndInsert(CRCHash
& rHash
, Bitmap
const& rBmp
, const char* pLocation
)
359 checkAndInsert(rHash
, rBmp
.GetChecksum(), pLocation
);
362 Bitmap
getAsBitmap(VclPtr
<OutputDevice
> const& pOut
)
364 return pOut
->GetBitmap(Point(), pOut
->GetOutputSizePixel());
367 void BitmapTest::testCRC()
371 Bitmap
aBitmap(Size(1023, 759), vcl::PixelFormat::N24_BPP
);
372 aBitmap
.Erase(COL_BLACK
);
373 checkAndInsert(aCRCs
, aBitmap
, "black bitmap");
375 checkAndInsert(aCRCs
, aBitmap
, "white bitmap");
377 ScopedVclPtrInstance
<VirtualDevice
> aVDev
;
378 aVDev
->SetBackground(Wallpaper(COL_WHITE
));
379 aVDev
->SetOutputSizePixel(Size(1023, 759));
381 #if 0 // disabled for now - oddly breaks on OS/X - but why ?
382 Bitmap aWhiteCheck
= getAsBitmap(aVDev
);
383 CPPUNIT_ASSERT(aCRCs
.find(aWhiteCheck
.GetChecksum()) != aCRCs
.end());
386 // a 1x1 black & white checkerboard
387 aVDev
->DrawCheckered(Point(), aVDev
->GetOutputSizePixel(), 1, Color(0, 0, 1));
388 Bitmap aChecker
= getAsBitmap(aVDev
);
389 checkAndInsert(aCRCs
, aChecker
, "checkerboard");
391 checkAndInsert(aCRCs
, aChecker
, "inverted checkerboard");
394 void BitmapTest::testGreyPalette()
397 BitmapPalette aPalette
= Bitmap::GetGreyPalette(2);
398 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16
>(2),
399 aPalette
.GetEntryCount());
400 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette
[0]);
401 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(255, 255, 255), aPalette
[1]);
405 BitmapPalette aPalette
= Bitmap::GetGreyPalette(4);
406 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16
>(4),
407 aPalette
.GetEntryCount());
408 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette
[0]);
409 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(85, 85, 85), aPalette
[1]);
410 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 3 wrong", BitmapColor(170, 170, 170), aPalette
[2]);
411 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 4 wrong", BitmapColor(255, 255, 255), aPalette
[3]);
415 BitmapPalette aPalette
= Bitmap::GetGreyPalette(16);
416 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16
>(16),
417 aPalette
.GetEntryCount());
418 // this is a *real* specific number of greys, incremented in units of 17 so may
419 // as well test them all...
420 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette
[0]);
421 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(17, 17, 17), aPalette
[1]);
422 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 3 wrong", BitmapColor(34, 34, 34), aPalette
[2]);
423 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 4 wrong", BitmapColor(51, 51, 51), aPalette
[3]);
424 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 5 wrong", BitmapColor(68, 68, 68), aPalette
[4]);
425 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 6 wrong", BitmapColor(85, 85, 85), aPalette
[5]);
426 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 7 wrong", BitmapColor(102, 102, 102), aPalette
[6]);
427 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 8 wrong", BitmapColor(119, 119, 119), aPalette
[7]);
428 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 9 wrong", BitmapColor(136, 136, 136), aPalette
[8]);
429 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 10 wrong", BitmapColor(153, 153, 153), aPalette
[9]);
430 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 11 wrong", BitmapColor(170, 170, 170), aPalette
[10]);
431 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 12 wrong", BitmapColor(187, 187, 187), aPalette
[11]);
432 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 13 wrong", BitmapColor(204, 204, 204), aPalette
[12]);
433 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 14 wrong", BitmapColor(221, 221, 221), aPalette
[13]);
434 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 15 wrong", BitmapColor(238, 238, 238), aPalette
[14]);
435 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 16 wrong", BitmapColor(255, 255, 255), aPalette
[15]);
439 BitmapPalette aPalette
= Bitmap::GetGreyPalette(256);
440 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries",
441 static_cast<sal_uInt16
>(256), aPalette
.GetEntryCount());
442 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette
[0]);
443 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 127 wrong", BitmapColor(127, 127, 127), aPalette
[127]);
444 CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 255 wrong", BitmapColor(255, 255, 255), aPalette
[255]);
448 void BitmapTest::testCustom8BitPalette()
450 BitmapPalette aCustomPalette
;
451 aCustomPalette
.SetEntryCount(256);
452 for (sal_uInt16 i
= 0; i
< 256; i
++)
454 aCustomPalette
[i
] = BitmapColor(sal_uInt8(i
), sal_uInt8(0xCC), sal_uInt8(0x22));
456 Bitmap
aBitmap(Size(3, 2), vcl::PixelFormat::N8_BPP
, &aCustomPalette
);
459 BitmapScopedWriteAccess
pAccess(aBitmap
);
460 pAccess
->SetPixelIndex(0, 0, 0);
461 pAccess
->SetPixelIndex(0, 1, 1);
462 pAccess
->SetPixelIndex(0, 2, 2);
464 pAccess
->SetPixelIndex(1, 0, 253);
465 pAccess
->SetPixelIndex(1, 1, 254);
466 pAccess
->SetPixelIndex(1, 2, 255);
470 Bitmap::ScopedReadAccess
pAccess(aBitmap
);
471 CPPUNIT_ASSERT_EQUAL(0, int(pAccess
->GetPixelIndex(0, 0)));
472 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xCC, 0x22), pAccess
->GetColor(0, 0));
474 CPPUNIT_ASSERT_EQUAL(1, int(pAccess
->GetPixelIndex(0, 1)));
475 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x01, 0xCC, 0x22), pAccess
->GetColor(0, 1));
477 CPPUNIT_ASSERT_EQUAL(2, int(pAccess
->GetPixelIndex(0, 2)));
478 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x02, 0xCC, 0x22), pAccess
->GetColor(0, 2));
480 CPPUNIT_ASSERT_EQUAL(253, int(pAccess
->GetPixelIndex(1, 0)));
481 CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFD, 0xCC, 0x22), pAccess
->GetColor(1, 0));
483 CPPUNIT_ASSERT_EQUAL(254, int(pAccess
->GetPixelIndex(1, 1)));
484 CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFE, 0xCC, 0x22), pAccess
->GetColor(1, 1));
486 CPPUNIT_ASSERT_EQUAL(255, int(pAccess
->GetPixelIndex(1, 2)));
487 CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xCC, 0x22), pAccess
->GetColor(1, 2));
491 void BitmapTest::testErase()
493 Bitmap
aBitmap(Size(3, 3), vcl::PixelFormat::N24_BPP
);
495 BitmapScopedWriteAccess
pWriteAccess(aBitmap
);
496 pWriteAccess
->Erase(Color(0x11, 0x22, 0x33));
499 Bitmap::ScopedReadAccess
pReadAccess(aBitmap
);
500 BitmapColor
aColor(pReadAccess
->GetPixel(0, 0));
501 CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency
, 0x11, 0x22, 0x33, 0x00), aColor
);
505 void BitmapTest::testBitmap32()
507 // Check backend capabilities and return from the test successfully
508 // if the backend doesn't support 32-bit bitmap
509 if (!ImplGetSVData()->mpDefInst
->supportsBitmap32())
512 Bitmap
aBitmap(Size(3, 3), vcl::PixelFormat::N32_BPP
);
514 BitmapScopedWriteAccess
pWriteAccess(aBitmap
);
515 pWriteAccess
->Erase(Color(ColorTransparency
, 0xFF, 0x11, 0x22, 0x33));
516 pWriteAccess
->SetPixel(1, 1, BitmapColor(ColorTransparency
, 0x44, 0xFF, 0xBB, 0x00));
517 pWriteAccess
->SetPixel(2, 2, BitmapColor(ColorTransparency
, 0x99, 0x77, 0x66, 0x55));
520 Bitmap::ScopedReadAccess
pReadAccess(aBitmap
);
521 BitmapColor aColor
= pReadAccess
->GetPixel(0, 0);
522 CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency
, 0x00, 0x00, 0x00, 0xFF), aColor
);
524 aColor
= pReadAccess
->GetPixel(1, 1);
525 CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency
, 0x44, 0xFF, 0xBB, 0x00), aColor
);
527 aColor
= pReadAccess
->GetPixel(2, 2);
528 CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency
, 0x99, 0x77, 0x66, 0x55), aColor
);
532 void BitmapTest::testOctree()
534 Size
aSize(1000, 100);
535 Bitmap
aBitmap(aSize
, vcl::PixelFormat::N24_BPP
);
537 BitmapScopedWriteAccess
pWriteAccess(aBitmap
);
538 for (tools::Long y
= 0; y
< aSize
.Height(); ++y
)
540 for (tools::Long x
= 0; x
< aSize
.Width(); ++x
)
542 double fPercent
= double(x
) / double(aSize
.Width());
543 pWriteAccess
->SetPixel(y
, x
,
544 BitmapColor(255.0 * fPercent
, 64.0 + (128.0 * fPercent
),
545 255.0 - 255.0 * fPercent
));
552 Bitmap::ScopedReadAccess
pAccess(aBitmap
);
553 Octree
aOctree(*pAccess
, 1);
554 auto aBitmapPalette
= aOctree
.GetPalette();
555 CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), aBitmapPalette
.GetEntryCount());
556 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7e, 0x7f, 0x7f), aBitmapPalette
[0]);
561 Bitmap::ScopedReadAccess
pAccess(aBitmap
);
562 Octree
aOctree(*pAccess
, 4);
563 auto aBitmapPalette
= aOctree
.GetPalette();
564 CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), aBitmapPalette
.GetEntryCount());
565 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7f, 0x7f, 0x7f), aBitmapPalette
[0]);
566 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x3e, 0x5f, 0xbf), aBitmapPalette
[1]);
567 CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7f, 0x80, 0x7f), aBitmapPalette
[2]);
568 CPPUNIT_ASSERT_EQUAL(BitmapColor(0xbe, 0x9f, 0x3f), aBitmapPalette
[3]);
572 // Reduce to 256 color
573 Bitmap::ScopedReadAccess
pAccess(aBitmap
);
574 Octree
aOctree(*pAccess
, 256);
575 auto aBitmapPalette
= aOctree
.GetPalette();
576 CPPUNIT_ASSERT_EQUAL(sal_uInt16(74), aBitmapPalette
.GetEntryCount());
580 void BitmapTest::testEmptyAccess()
583 BitmapInfoAccess
access(empty
);
584 CPPUNIT_ASSERT_EQUAL(tools::Long(0), access
.Width());
585 CPPUNIT_ASSERT_EQUAL(tools::Long(0), access
.Height());
588 void BitmapTest::testDitherSize()
590 // no need to do anything for a 1x1 pixel bitmap
592 Bitmap
aBitmap(Size(1, 1), vcl::PixelFormat::N24_BPP
);
593 CPPUNIT_ASSERT(aBitmap
.Dither());
596 // cannot dither a bitmap with a width of 2 or 3 pixels
598 Bitmap
aBitmap(Size(2, 4), vcl::PixelFormat::N24_BPP
);
599 CPPUNIT_ASSERT(!aBitmap
.Dither());
603 Bitmap
aBitmap(Size(3, 4), vcl::PixelFormat::N24_BPP
);
604 CPPUNIT_ASSERT(!aBitmap
.Dither());
607 // cannot dither a bitmap with a height of 2 pixels
609 Bitmap
aBitmap(Size(4, 2), vcl::PixelFormat::N24_BPP
);
610 CPPUNIT_ASSERT(!aBitmap
.Dither());
613 // only dither bitmaps with a width > 3 pixels and height > 2 pixels
615 Bitmap
aBitmap(Size(4, 3), vcl::PixelFormat::N24_BPP
);
616 CPPUNIT_ASSERT(aBitmap
.Dither());
620 void BitmapTest::testMirror()
622 vcl::PixelFormat bppArray
[]
623 = { vcl::PixelFormat::N8_BPP
, vcl::PixelFormat::N24_BPP
, vcl::PixelFormat::N32_BPP
};
625 for (vcl::PixelFormat bpp
: bppArray
)
627 Bitmap
bitmap(Size(11, 11), bpp
);
629 bitmap
.Erase(COL_MAGENTA
);
630 BitmapWriteAccess
write(bitmap
);
631 if (write
.HasPalette())
633 // Note that SetPixel() and GetColor() take arguments as Y,X.
634 write
.SetPixel(0, 0, BitmapColor(write
.GetBestPaletteIndex(COL_BLACK
)));
635 write
.SetPixel(10, 0, BitmapColor(write
.GetBestPaletteIndex(COL_WHITE
)));
636 write
.SetPixel(0, 10, BitmapColor(write
.GetBestPaletteIndex(COL_RED
)));
637 write
.SetPixel(10, 10, BitmapColor(write
.GetBestPaletteIndex(COL_BLUE
)));
638 write
.SetPixel(5, 0, BitmapColor(write
.GetBestPaletteIndex(COL_GREEN
)));
639 write
.SetPixel(0, 5, BitmapColor(write
.GetBestPaletteIndex(COL_YELLOW
)));
643 write
.SetPixel(0, 0, COL_BLACK
);
644 write
.SetPixel(10, 0, COL_WHITE
);
645 write
.SetPixel(0, 10, COL_RED
);
646 write
.SetPixel(10, 10, COL_BLUE
);
647 write
.SetPixel(5, 0, COL_GREEN
);
648 write
.SetPixel(0, 5, COL_YELLOW
);
651 bitmap
.Mirror(BmpMirrorFlags::Horizontal
);
653 BitmapReadAccess
read(bitmap
);
654 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK
), read
.GetColor(0, 10));
655 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE
), read
.GetColor(10, 10));
656 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED
), read
.GetColor(0, 0));
657 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE
), read
.GetColor(10, 0));
658 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN
), read
.GetColor(5, 10));
659 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW
), read
.GetColor(0, 5));
661 bitmap
.Mirror(BmpMirrorFlags::Vertical
);
663 BitmapReadAccess
read(bitmap
);
664 // Now is effectively mirrored in both directions.
665 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK
), read
.GetColor(10, 10));
666 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE
), read
.GetColor(0, 10));
667 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED
), read
.GetColor(10, 0));
668 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE
), read
.GetColor(0, 0));
669 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN
), read
.GetColor(5, 10));
670 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW
), read
.GetColor(10, 5));
672 bitmap
.Mirror(BmpMirrorFlags::Vertical
| BmpMirrorFlags::Horizontal
);
674 BitmapReadAccess
read(bitmap
);
675 // Now is back the original.
676 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK
), read
.GetColor(0, 0));
677 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE
), read
.GetColor(10, 0));
678 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED
), read
.GetColor(0, 10));
679 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE
), read
.GetColor(10, 10));
680 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN
), read
.GetColor(5, 0));
681 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW
), read
.GetColor(0, 5));
686 void BitmapTest::testCroppedDownsampledBitmap()
688 Bitmap
aBitmap(Size(16, 16), vcl::PixelFormat::N24_BPP
);
689 Bitmap
aDownsampledBmp(vcl::bitmap::GetDownsampledBitmap(Size(10, 10), Point(20, 20),
690 Size(5, 5), aBitmap
, 72, 72));
691 CPPUNIT_ASSERT(aDownsampledBmp
.IsEmpty());
694 void BitmapTest::testCrop()
696 Bitmap
aBitmap(Bitmap(Size(16, 16), vcl::PixelFormat::N24_BPP
));
699 Bitmap
aCroppedBmp(aBitmap
);
700 CPPUNIT_ASSERT_MESSAGE("Crop was fully outside of bitmap bounds",
701 !aCroppedBmp
.Crop(tools::Rectangle(Point(20, 20), Size(5, 5))));
702 CPPUNIT_ASSERT_EQUAL(Size(16, 16), aCroppedBmp
.GetSizePixel());
706 Bitmap
aCroppedBmp(aBitmap
);
707 CPPUNIT_ASSERT_MESSAGE("Crop same size as bitmap",
708 !aCroppedBmp
.Crop(tools::Rectangle(Point(0, 0), Size(16, 16))));
709 CPPUNIT_ASSERT_EQUAL(Size(16, 16), aCroppedBmp
.GetSizePixel());
713 Bitmap
aCroppedBmp(aBitmap
);
714 CPPUNIT_ASSERT_MESSAGE("Crop larger than bitmap",
715 !aCroppedBmp
.Crop(tools::Rectangle(Point(0, 0), Size(100, 100))));
716 CPPUNIT_ASSERT_EQUAL(Size(16, 16), aCroppedBmp
.GetSizePixel());
720 Bitmap
aCroppedBmp(aBitmap
);
721 CPPUNIT_ASSERT_MESSAGE("Crop partially overcrops bitmap",
722 aCroppedBmp
.Crop(tools::Rectangle(Point(10, 10), Size(100, 100))));
723 CPPUNIT_ASSERT_EQUAL(Size(6, 6), aCroppedBmp
.GetSizePixel());
727 Bitmap
aCroppedBmp(aBitmap
);
728 CPPUNIT_ASSERT_MESSAGE("Crop inside bitmap",
729 aCroppedBmp
.Crop(tools::Rectangle(Point(5, 5), Size(10, 10))));
730 CPPUNIT_ASSERT_EQUAL(Size(10, 10), aCroppedBmp
.GetSizePixel());
735 CPPUNIT_TEST_SUITE_REGISTRATION(BitmapTest
);
737 CPPUNIT_PLUGIN_IMPLEMENT();
739 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */