xref: /core/vcl/qa/cppunit/BitmapTest.cxx (revision 088a7c7c451321a800ca8d3523a18b6bb93239b7)
1 /*
2  * This file is part of the LibreOffice project.
3  *
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/.
7  */
8 
9 #include <cppunit/TestAssert.h>
10 #include <cppunit/TestFixture.h>
11 #include <cppunit/extensions/HelperMacros.h>
12 #include <cppunit/plugin/TestPlugIn.h>
13 
14 #include <vcl/BitmapTools.hxx>
15 #include <vcl/BitmapWriteAccess.hxx>
16 #include <vcl/bitmap/BitmapMonochromeFilter.hxx>
17 #include <vcl/virdev.hxx>
18 #include <vcl/skia/SkiaHelper.hxx>
19 
20 #include <bitmap/Octree.hxx>
21 #include <salinst.hxx>
22 #include <svdata.hxx>
23 
24 #include <unordered_map>
25 
26 namespace
27 {
28 class BitmapTest : public CppUnit::TestFixture
29 {
30     void testCreation();
31     void testEmpty();
32     void testMonochrome();
33     void testN8Greyscale();
34     void testConvert();
35     void testCRC();
36     void testGreyPalette();
37     void testCustom8BitPalette();
38     void testErase();
39     void testBitmap32();
40     void testOctree();
41     void testEmptyAccess();
42     void testDitherSize();
43     void testMirror();
44     void testCrop();
45     void testCroppedDownsampledBitmap();
46 
47     CPPUNIT_TEST_SUITE(BitmapTest);
48     CPPUNIT_TEST(testCreation);
49     CPPUNIT_TEST(testEmpty);
50     CPPUNIT_TEST(testMonochrome);
51     CPPUNIT_TEST(testConvert);
52     CPPUNIT_TEST(testN8Greyscale);
53     CPPUNIT_TEST(testCRC);
54     CPPUNIT_TEST(testGreyPalette);
55     CPPUNIT_TEST(testCustom8BitPalette);
56     CPPUNIT_TEST(testErase);
57     CPPUNIT_TEST(testBitmap32);
58     CPPUNIT_TEST(testOctree);
59     CPPUNIT_TEST(testEmptyAccess);
60     CPPUNIT_TEST(testDitherSize);
61     CPPUNIT_TEST(testMirror);
62     CPPUNIT_TEST(testCrop);
63     CPPUNIT_TEST(testCroppedDownsampledBitmap);
64     CPPUNIT_TEST_SUITE_END();
65 };
66 
assertColorsAreSimilar(int maxDifference,const std::string & message,const BitmapColor & expected,const BitmapColor & actual)67 void assertColorsAreSimilar(int maxDifference, const std::string& message,
68                             const BitmapColor& expected, const BitmapColor& actual)
69 {
70     // Check that the two colors match or are reasonably similar.
71     if (expected.GetColorError(actual) <= maxDifference)
72         return;
73     CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual);
74 }
75 
testCreation()76 void BitmapTest::testCreation()
77 {
78     {
79         Bitmap aBmp;
80         Size aSize = aBmp.GetSizePixel();
81         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long>(0), aSize.Width());
82         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long>(0), aSize.Height());
83         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize());
84         CPPUNIT_ASSERT_MESSAGE("Not empty", aBmp.IsEmpty());
85         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::INVALID,
86                                      aBmp.getPixelFormat());
87         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_Int64>(0),
88                                      aBmp.GetSizeBytes());
89     }
90 
91     {
92         Bitmap aBmp(Size(10, 10), vcl::PixelFormat::N8_BPP);
93         Size aSize = aBmp.GetSizePixel();
94         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long>(10), aSize.Width());
95         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long>(10), aSize.Height());
96         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize());
97         CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty());
98         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::N8_BPP,
99                                      aBmp.getPixelFormat());
100         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_Int64>(100),
101                                      aBmp.GetSizeBytes());
102     }
103 
104     {
105         Bitmap aBmp(Size(10, 10), vcl::PixelFormat::N24_BPP);
106         Size aSize = aBmp.GetSizePixel();
107         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long>(10), aSize.Width());
108         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long>(10), aSize.Height());
109         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize());
110         CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty());
111         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::N24_BPP,
112                                      aBmp.getPixelFormat());
113         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_Int64>(300),
114                                      aBmp.GetSizeBytes());
115     }
116 
117     // Check backend capabilities and return from the test successfully
118     {
119         Bitmap aBmp(Size(10, 10), vcl::PixelFormat::N32_BPP);
120         Size aSize = aBmp.GetSizePixel();
121         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<tools::Long>(10), aSize.Width());
122         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<tools::Long>(10), aSize.Height());
123         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize());
124         CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty());
125         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pixel format", vcl::PixelFormat::N32_BPP,
126                                      aBmp.getPixelFormat());
127         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", sal_Int64(400), aBmp.GetSizeBytes());
128     }
129 }
130 
testEmpty()131 void BitmapTest::testEmpty()
132 {
133     Bitmap aBitmap(Size(10, 10), vcl::PixelFormat::N8_BPP);
134     aBitmap.Erase(COL_LIGHTGRAYBLUE);
135 
136     CPPUNIT_ASSERT(!aBitmap.IsEmpty());
137 
138     aBitmap.SetEmpty();
139     CPPUNIT_ASSERT(aBitmap.IsEmpty());
140 }
141 
createTestBitmap()142 Bitmap createTestBitmap()
143 {
144     Bitmap aBmp(Size(4, 4), vcl::PixelFormat::N24_BPP);
145     BitmapWriteAccess aBmpAccess(aBmp);
146 
147     // row 1
148     aBmpAccess.SetPixel(0, 0, BitmapColor(COL_BLACK));
149     aBmpAccess.SetPixel(0, 1, BitmapColor(COL_BLUE));
150     aBmpAccess.SetPixel(0, 2, BitmapColor(COL_GREEN));
151     aBmpAccess.SetPixel(0, 3, BitmapColor(COL_CYAN));
152 
153     // row 2
154     aBmpAccess.SetPixel(1, 0, BitmapColor(COL_RED));
155     aBmpAccess.SetPixel(1, 1, BitmapColor(COL_MAGENTA));
156     aBmpAccess.SetPixel(1, 2, BitmapColor(COL_BROWN));
157     aBmpAccess.SetPixel(1, 3, BitmapColor(COL_GRAY));
158 
159     // row 3
160     aBmpAccess.SetPixel(2, 0, BitmapColor(COL_LIGHTGRAY));
161     aBmpAccess.SetPixel(2, 1, BitmapColor(COL_LIGHTBLUE));
162     aBmpAccess.SetPixel(2, 2, BitmapColor(COL_LIGHTGREEN));
163     aBmpAccess.SetPixel(2, 3, BitmapColor(COL_LIGHTCYAN));
164 
165     // row 4
166     aBmpAccess.SetPixel(3, 0, BitmapColor(COL_LIGHTRED));
167     aBmpAccess.SetPixel(3, 1, BitmapColor(COL_LIGHTMAGENTA));
168     aBmpAccess.SetPixel(3, 2, BitmapColor(COL_YELLOW));
169     aBmpAccess.SetPixel(3, 3, BitmapColor(COL_WHITE));
170 
171     return aBmp;
172 }
173 
testMonochrome()174 void BitmapTest::testMonochrome()
175 {
176     Bitmap aBmp = createTestBitmap();
177 
178     BitmapEx aBmpEx(aBmp);
179     BitmapFilter::Filter(aBmpEx, BitmapMonochromeFilter(63));
180     aBmp = aBmpEx.GetBitmap();
181     BitmapReadAccess aBmpReadAccess(aBmp);
182 
183     CPPUNIT_ASSERT_EQUAL_MESSAGE("Black pixel wrong monochrome value", BitmapColor(COL_BLACK),
184                                  aBmpReadAccess.GetColor(0, 0));
185     CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue pixel wrong monochrome value", BitmapColor(COL_BLACK),
186                                  aBmpReadAccess.GetColor(0, 1));
187     CPPUNIT_ASSERT_EQUAL_MESSAGE("Green pixel wrong monochrome value", BitmapColor(COL_WHITE),
188                                  aBmpReadAccess.GetColor(0, 2));
189     CPPUNIT_ASSERT_EQUAL_MESSAGE("Cyan pixel wrong monochrome value", BitmapColor(COL_WHITE),
190                                  aBmpReadAccess.GetColor(0, 3));
191     CPPUNIT_ASSERT_EQUAL_MESSAGE("Red pixel wrong monochrome value", BitmapColor(COL_BLACK),
192                                  aBmpReadAccess.GetColor(1, 0));
193     CPPUNIT_ASSERT_EQUAL_MESSAGE("Magenta pixel wrong monochrome value", BitmapColor(COL_BLACK),
194                                  aBmpReadAccess.GetColor(1, 1));
195     CPPUNIT_ASSERT_EQUAL_MESSAGE("Brown pixel wrong monochrome value", BitmapColor(COL_WHITE),
196                                  aBmpReadAccess.GetColor(1, 2));
197     CPPUNIT_ASSERT_EQUAL_MESSAGE("Gray pixel wrong monochrome value", BitmapColor(COL_WHITE),
198                                  aBmpReadAccess.GetColor(1, 3));
199     CPPUNIT_ASSERT_EQUAL_MESSAGE("Light gray pixel wrong monochrome value", BitmapColor(COL_WHITE),
200                                  aBmpReadAccess.GetColor(2, 0));
201     CPPUNIT_ASSERT_EQUAL_MESSAGE("Light blue pixel wrong monochrome value", BitmapColor(COL_BLACK),
202                                  aBmpReadAccess.GetColor(2, 1));
203     CPPUNIT_ASSERT_EQUAL_MESSAGE("Light green pixel wrong monochrome value", BitmapColor(COL_WHITE),
204                                  aBmpReadAccess.GetColor(2, 2));
205     CPPUNIT_ASSERT_EQUAL_MESSAGE("Light cyan pixel wrong monochrome value", BitmapColor(COL_WHITE),
206                                  aBmpReadAccess.GetColor(2, 3));
207     CPPUNIT_ASSERT_EQUAL_MESSAGE("Light red pixel wrong monochrome value", BitmapColor(COL_WHITE),
208                                  aBmpReadAccess.GetColor(3, 0));
209     CPPUNIT_ASSERT_EQUAL_MESSAGE("Light magenta pixel wrong monochrome value",
210                                  BitmapColor(COL_WHITE), aBmpReadAccess.GetColor(3, 1));
211     CPPUNIT_ASSERT_EQUAL_MESSAGE("Yellow pixel wrong monochrome value", BitmapColor(COL_WHITE),
212                                  aBmpReadAccess.GetColor(3, 2));
213     CPPUNIT_ASSERT_EQUAL_MESSAGE("White pixel wrong monochrome value", BitmapColor(COL_WHITE),
214                                  aBmpReadAccess.GetColor(3, 3));
215 }
216 
testN8Greyscale()217 void BitmapTest::testN8Greyscale()
218 {
219     Bitmap aBmp = createTestBitmap();
220     BitmapPalette aGreyscalePalette = Bitmap::GetGreyPalette(256);
221 
222     aBmp.Convert(BmpConversion::N8BitGreys);
223     BitmapReadAccess aBmpReadAccess(aBmp);
224 
225     assertColorsAreSimilar(1, "Black pixel wrong 8-bit greyscale value", aGreyscalePalette[0],
226                            aBmpReadAccess.GetColor(0, 0));
227     assertColorsAreSimilar(1, "Blue pixel wrong 8-bit greyscale value", aGreyscalePalette[14],
228                            aBmpReadAccess.GetColor(0, 1));
229     assertColorsAreSimilar(1, "Green pixel wrong 8-bit greyscale value", aGreyscalePalette[75],
230                            aBmpReadAccess.GetColor(0, 2));
231     assertColorsAreSimilar(1, "Cyan pixel wrong 8-bit greyscale value", aGreyscalePalette[89],
232                            aBmpReadAccess.GetColor(0, 3));
233     assertColorsAreSimilar(1, "Red pixel wrong 8-bit greyscale value", aGreyscalePalette[38],
234                            aBmpReadAccess.GetColor(1, 0));
235     assertColorsAreSimilar(1, "Magenta pixel wrong 8-bit greyscale value", aGreyscalePalette[52],
236                            aBmpReadAccess.GetColor(1, 1));
237     assertColorsAreSimilar(1, "Brown pixel wrong 8-bit greyscale value", aGreyscalePalette[114],
238                            aBmpReadAccess.GetColor(1, 2));
239     assertColorsAreSimilar(1, "Gray pixel wrong 8-bit greyscale value", aGreyscalePalette[128],
240                            aBmpReadAccess.GetColor(1, 3));
241     assertColorsAreSimilar(1, "Light gray pixel wrong 8-bit greyscale value",
242                            aGreyscalePalette[192], aBmpReadAccess.GetColor(2, 0));
243     assertColorsAreSimilar(1, "Light blue pixel wrong 8-bit greyscale value", aGreyscalePalette[27],
244                            aBmpReadAccess.GetColor(2, 1));
245     assertColorsAreSimilar(1, "Light green pixel wrong 8-bit greyscale value",
246                            aGreyscalePalette[150], aBmpReadAccess.GetColor(2, 2));
247     assertColorsAreSimilar(1, "Light cyan pixel wrong 8-bit greyscale value",
248                            aGreyscalePalette[178], aBmpReadAccess.GetColor(2, 3));
249     assertColorsAreSimilar(1, "Light red pixel wrong 8-bit greyscale value", aGreyscalePalette[76],
250                            aBmpReadAccess.GetColor(3, 0));
251     assertColorsAreSimilar(1, "Light magenta pixel wrong 8-bit greyscale value",
252                            aGreyscalePalette[104], aBmpReadAccess.GetColor(3, 1));
253     assertColorsAreSimilar(1, "Yellow pixel wrong 8-bit greyscale value", aGreyscalePalette[227],
254                            aBmpReadAccess.GetColor(3, 2));
255     assertColorsAreSimilar(1, "White pixel wrong 8-bit greyscale value", aGreyscalePalette[255],
256                            aBmpReadAccess.GetColor(3, 3));
257 }
258 
testConvert()259 void BitmapTest::testConvert()
260 {
261     Bitmap aBitmap(Size(10, 10), vcl::PixelFormat::N8_BPP);
262 
263     aBitmap.Erase(COL_LIGHTGRAYBLUE);
264 
265     CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP, aBitmap.getPixelFormat());
266     {
267         BitmapScopedReadAccess pReadAccess(aBitmap);
268         CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(8), pReadAccess->GetBitCount());
269 #if defined MACOSX || defined IOS
270         if (SkiaHelper::isVCLSkiaEnabled())
271             CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(12), pReadAccess->GetScanlineSize());
272         else
273             //it would be nice to find and change the stride for quartz to be the same as everyone else
274             CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(10), pReadAccess->GetScanlineSize());
275 #else
276         CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(12), pReadAccess->GetScanlineSize());
277 #endif
278         CPPUNIT_ASSERT(pReadAccess->HasPalette());
279         const BitmapColor& rColor = pReadAccess->GetPaletteColor(pReadAccess->GetPixelIndex(1, 1));
280         CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(rColor.GetRed()));
281         CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(rColor.GetGreen()));
282         CPPUNIT_ASSERT_EQUAL(sal_Int32(255), sal_Int32(rColor.GetBlue()));
283     }
284 
285     aBitmap.Convert(BmpConversion::N24Bit);
286 
287     CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP, aBitmap.getPixelFormat());
288     {
289         BitmapScopedReadAccess pReadAccess(aBitmap);
290         // 24 bit Bitmap on SVP backend can now use 24bit RGB everywhere.
291         CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(24), pReadAccess->GetBitCount());
292 
293         if (SkiaHelper::isVCLSkiaEnabled()) // aligned to 4 bytes
294             CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess->GetScanlineSize());
295         else
296 #if defined LINUX || defined FREEBSD
297         {
298             CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess->GetScanlineSize());
299         }
300 #elif defined(_WIN32)
301         {
302             // GDI Scanlines padded to DWORD multiples, it seems
303             CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess->GetScanlineSize());
304         }
305 #else
306         {
307             CPPUNIT_ASSERT_EQUAL(sal_uInt32(30), pReadAccess->GetScanlineSize());
308         }
309 #endif
310 
311         CPPUNIT_ASSERT(!pReadAccess->HasPalette());
312         Color aColor = pReadAccess->GetPixel(0, 0);
313         CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor.GetRed()));
314         CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor.GetGreen()));
315         CPPUNIT_ASSERT_EQUAL(sal_Int32(255), sal_Int32(aColor.GetBlue()));
316     }
317 }
318 
319 typedef std::unordered_map<sal_uInt64, const char*> CRCHash;
320 
checkAndInsert(CRCHash & rHash,sal_uInt64 nCRC,const char * pLocation)321 void checkAndInsert(CRCHash& rHash, sal_uInt64 nCRC, const char* pLocation)
322 {
323     auto it = rHash.find(nCRC);
324     if (it != rHash.end())
325     {
326         OString aBuf = OString::Concat("CRC collision between ") + pLocation + " and " + it->second
327                        + " hash is 0x" + OString::number(static_cast<sal_Int64>(nCRC), 16);
328         CPPUNIT_FAIL(aBuf.getStr());
329     }
330     rHash[nCRC] = pLocation;
331 }
332 
checkAndInsert(CRCHash & rHash,Bitmap const & rBmp,const char * pLocation)333 void checkAndInsert(CRCHash& rHash, Bitmap const& rBmp, const char* pLocation)
334 {
335     checkAndInsert(rHash, rBmp.GetChecksum(), pLocation);
336 }
337 
getAsBitmap(VclPtr<OutputDevice> const & pOut)338 Bitmap getAsBitmap(VclPtr<OutputDevice> const& pOut)
339 {
340     return pOut->GetBitmap(Point(), pOut->GetOutputSizePixel());
341 }
342 
testCRC()343 void BitmapTest::testCRC()
344 {
345     CRCHash aCRCs;
346 
347     Bitmap aBitmap(Size(1023, 759), vcl::PixelFormat::N24_BPP);
348     aBitmap.Erase(COL_BLACK);
349     checkAndInsert(aCRCs, aBitmap, "black bitmap");
350     aBitmap.Invert();
351     checkAndInsert(aCRCs, aBitmap, "white bitmap");
352 
353     ScopedVclPtrInstance<VirtualDevice> aVDev;
354     aVDev->SetBackground(Wallpaper(COL_WHITE));
355     aVDev->SetOutputSizePixel(Size(1023, 759));
356 
357 #if 0 // disabled for now - oddly breaks on OS/X - but why ?
358     Bitmap aWhiteCheck = getAsBitmap(aVDev);
359     CPPUNIT_ASSERT(aCRCs.find(aWhiteCheck.GetChecksum()) != aCRCs.end());
360 #endif
361 
362     // a 1x1 black & white checkerboard
363     aVDev->DrawCheckered(Point(), aVDev->GetOutputSizePixel(), 1, Color(0, 0, 1));
364     Bitmap aChecker = getAsBitmap(aVDev);
365     checkAndInsert(aCRCs, aChecker, "checkerboard");
366     aChecker.Invert();
367     checkAndInsert(aCRCs, aChecker, "inverted checkerboard");
368 }
369 
testGreyPalette()370 void BitmapTest::testGreyPalette()
371 {
372     {
373         BitmapPalette aPalette = Bitmap::GetGreyPalette(2);
374         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16>(2),
375                                      aPalette.GetEntryCount());
376         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]);
377         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(255, 255, 255), aPalette[1]);
378     }
379 
380     {
381         BitmapPalette aPalette = Bitmap::GetGreyPalette(4);
382         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16>(4),
383                                      aPalette.GetEntryCount());
384         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]);
385         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(85, 85, 85), aPalette[1]);
386         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 3 wrong", BitmapColor(170, 170, 170), aPalette[2]);
387         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 4 wrong", BitmapColor(255, 255, 255), aPalette[3]);
388     }
389 
390     {
391         BitmapPalette aPalette = Bitmap::GetGreyPalette(16);
392         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16>(16),
393                                      aPalette.GetEntryCount());
394         // this is a *real* specific number of greys, incremented in units of 17 so may
395         // as well test them all...
396         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]);
397         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(17, 17, 17), aPalette[1]);
398         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 3 wrong", BitmapColor(34, 34, 34), aPalette[2]);
399         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 4 wrong", BitmapColor(51, 51, 51), aPalette[3]);
400         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 5 wrong", BitmapColor(68, 68, 68), aPalette[4]);
401         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 6 wrong", BitmapColor(85, 85, 85), aPalette[5]);
402         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 7 wrong", BitmapColor(102, 102, 102), aPalette[6]);
403         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 8 wrong", BitmapColor(119, 119, 119), aPalette[7]);
404         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 9 wrong", BitmapColor(136, 136, 136), aPalette[8]);
405         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 10 wrong", BitmapColor(153, 153, 153), aPalette[9]);
406         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 11 wrong", BitmapColor(170, 170, 170), aPalette[10]);
407         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 12 wrong", BitmapColor(187, 187, 187), aPalette[11]);
408         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 13 wrong", BitmapColor(204, 204, 204), aPalette[12]);
409         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 14 wrong", BitmapColor(221, 221, 221), aPalette[13]);
410         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 15 wrong", BitmapColor(238, 238, 238), aPalette[14]);
411         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 16 wrong", BitmapColor(255, 255, 255), aPalette[15]);
412     }
413 
414     {
415         BitmapPalette aPalette = Bitmap::GetGreyPalette(256);
416         CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries",
417                                      static_cast<sal_uInt16>(256), aPalette.GetEntryCount());
418         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]);
419         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 127 wrong", BitmapColor(127, 127, 127), aPalette[127]);
420         CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 255 wrong", BitmapColor(255, 255, 255), aPalette[255]);
421     }
422 }
423 
testCustom8BitPalette()424 void BitmapTest::testCustom8BitPalette()
425 {
426     BitmapPalette aCustomPalette;
427     aCustomPalette.SetEntryCount(256);
428     for (sal_uInt16 i = 0; i < 256; i++)
429     {
430         aCustomPalette[i] = BitmapColor(sal_uInt8(i), sal_uInt8(0xCC), sal_uInt8(0x22));
431     }
432     Bitmap aBitmap(Size(3, 2), vcl::PixelFormat::N8_BPP, &aCustomPalette);
433 
434     {
435         BitmapScopedWriteAccess pAccess(aBitmap);
436         pAccess->SetPixelIndex(0, 0, 0);
437         pAccess->SetPixelIndex(0, 1, 1);
438         pAccess->SetPixelIndex(0, 2, 2);
439 
440         pAccess->SetPixelIndex(1, 0, 253);
441         pAccess->SetPixelIndex(1, 1, 254);
442         pAccess->SetPixelIndex(1, 2, 255);
443     }
444 
445     {
446         BitmapScopedReadAccess pAccess(aBitmap);
447         CPPUNIT_ASSERT_EQUAL(0, int(pAccess->GetPixelIndex(0, 0)));
448         CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xCC, 0x22), pAccess->GetColor(0, 0));
449 
450         CPPUNIT_ASSERT_EQUAL(1, int(pAccess->GetPixelIndex(0, 1)));
451         CPPUNIT_ASSERT_EQUAL(BitmapColor(0x01, 0xCC, 0x22), pAccess->GetColor(0, 1));
452 
453         CPPUNIT_ASSERT_EQUAL(2, int(pAccess->GetPixelIndex(0, 2)));
454         CPPUNIT_ASSERT_EQUAL(BitmapColor(0x02, 0xCC, 0x22), pAccess->GetColor(0, 2));
455 
456         CPPUNIT_ASSERT_EQUAL(253, int(pAccess->GetPixelIndex(1, 0)));
457         CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFD, 0xCC, 0x22), pAccess->GetColor(1, 0));
458 
459         CPPUNIT_ASSERT_EQUAL(254, int(pAccess->GetPixelIndex(1, 1)));
460         CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFE, 0xCC, 0x22), pAccess->GetColor(1, 1));
461 
462         CPPUNIT_ASSERT_EQUAL(255, int(pAccess->GetPixelIndex(1, 2)));
463         CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xCC, 0x22), pAccess->GetColor(1, 2));
464     }
465 }
466 
testErase()467 void BitmapTest::testErase()
468 {
469     Bitmap aBitmap(Size(3, 3), vcl::PixelFormat::N24_BPP);
470     {
471         BitmapScopedWriteAccess pWriteAccess(aBitmap);
472         pWriteAccess->Erase(Color(0x11, 0x22, 0x33));
473     }
474     {
475         BitmapScopedReadAccess pReadAccess(aBitmap);
476         BitmapColor aColor(pReadAccess->GetPixel(0, 0));
477         CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x11, 0x22, 0x33, 0x00), aColor);
478     }
479 }
480 
testBitmap32()481 void BitmapTest::testBitmap32()
482 {
483     Bitmap aBitmap(Size(3, 3), vcl::PixelFormat::N32_BPP);
484     {
485         BitmapScopedWriteAccess pWriteAccess(aBitmap);
486         pWriteAccess->Erase(Color(ColorTransparency, 0xFF, 0x11, 0x22, 0x33));
487         pWriteAccess->SetPixel(1, 1, BitmapColor(ColorTransparency, 0x44, 0xFF, 0xBB, 0x00));
488         pWriteAccess->SetPixel(2, 2, BitmapColor(ColorTransparency, 0x99, 0x77, 0x66, 0x55));
489     }
490     {
491         BitmapScopedReadAccess pReadAccess(aBitmap);
492         BitmapColor aColor = pReadAccess->GetPixel(0, 0);
493         CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x00, 0xFF), aColor);
494 
495         aColor = pReadAccess->GetPixel(1, 1);
496         CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x44, 0xFF, 0xBB, 0x00), aColor);
497 
498         aColor = pReadAccess->GetPixel(2, 2);
499         CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x99, 0x77, 0x66, 0x55), aColor);
500     }
501 }
502 
testOctree()503 void BitmapTest::testOctree()
504 {
505     Size aSize(1000, 100);
506     Bitmap aBitmap(aSize, vcl::PixelFormat::N24_BPP);
507     {
508         BitmapScopedWriteAccess pWriteAccess(aBitmap);
509         for (tools::Long y = 0; y < aSize.Height(); ++y)
510         {
511             for (tools::Long x = 0; x < aSize.Width(); ++x)
512             {
513                 double fPercent = double(x) / double(aSize.Width());
514                 pWriteAccess->SetPixel(y, x,
515                                        BitmapColor(255.0 * fPercent, 64.0 + (128.0 * fPercent),
516                                                    255.0 - 255.0 * fPercent));
517             }
518         }
519     }
520 
521     {
522         // Reduce to 1 color
523         BitmapScopedReadAccess pAccess(aBitmap);
524         Octree aOctree(*pAccess, 1);
525         auto aBitmapPalette = aOctree.GetPalette();
526         CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), aBitmapPalette.GetEntryCount());
527         CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7e, 0x7f, 0x7f), aBitmapPalette[0]);
528     }
529 
530     {
531         // Reduce to 4 color
532         BitmapScopedReadAccess pAccess(aBitmap);
533         Octree aOctree(*pAccess, 4);
534         auto aBitmapPalette = aOctree.GetPalette();
535         CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), aBitmapPalette.GetEntryCount());
536         CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7f, 0x7f, 0x7f), aBitmapPalette[0]);
537         CPPUNIT_ASSERT_EQUAL(BitmapColor(0x3e, 0x5f, 0xbf), aBitmapPalette[1]);
538         CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7f, 0x80, 0x7f), aBitmapPalette[2]);
539         CPPUNIT_ASSERT_EQUAL(BitmapColor(0xbe, 0x9f, 0x3f), aBitmapPalette[3]);
540     }
541 
542     {
543         // Reduce to 256 color
544         BitmapScopedReadAccess pAccess(aBitmap);
545         Octree aOctree(*pAccess, 256);
546         auto aBitmapPalette = aOctree.GetPalette();
547         CPPUNIT_ASSERT_EQUAL(sal_uInt16(74), aBitmapPalette.GetEntryCount());
548     }
549 }
550 
testEmptyAccess()551 void BitmapTest::testEmptyAccess()
552 {
553     Bitmap empty;
554     BitmapInfoAccess access(empty);
555     CPPUNIT_ASSERT_EQUAL(tools::Long(0), access.Width());
556     CPPUNIT_ASSERT_EQUAL(tools::Long(0), access.Height());
557 }
558 
testDitherSize()559 void BitmapTest::testDitherSize()
560 {
561     // no need to do anything for a 1x1 pixel bitmap
562     {
563         Bitmap aBitmap(Size(1, 1), vcl::PixelFormat::N24_BPP);
564         CPPUNIT_ASSERT(aBitmap.Dither());
565     }
566 
567     // cannot dither a bitmap with a width of 2 or 3 pixels
568     {
569         Bitmap aBitmap(Size(2, 4), vcl::PixelFormat::N24_BPP);
570         CPPUNIT_ASSERT(!aBitmap.Dither());
571     }
572 
573     {
574         Bitmap aBitmap(Size(3, 4), vcl::PixelFormat::N24_BPP);
575         CPPUNIT_ASSERT(!aBitmap.Dither());
576     }
577 
578     // cannot dither a bitmap with a height of 2 pixels
579     {
580         Bitmap aBitmap(Size(4, 2), vcl::PixelFormat::N24_BPP);
581         CPPUNIT_ASSERT(!aBitmap.Dither());
582     }
583 
584     // only dither bitmaps with a width > 3 pixels and height > 2 pixels
585     {
586         Bitmap aBitmap(Size(4, 3), vcl::PixelFormat::N24_BPP);
587         CPPUNIT_ASSERT(aBitmap.Dither());
588     }
589 }
590 
testMirror()591 void BitmapTest::testMirror()
592 {
593     vcl::PixelFormat bppArray[]
594         = { vcl::PixelFormat::N8_BPP, vcl::PixelFormat::N24_BPP, vcl::PixelFormat::N32_BPP };
595 
596     for (vcl::PixelFormat bpp : bppArray)
597     {
598         Bitmap bitmap(Size(11, 11), bpp);
599         {
600             bitmap.Erase(COL_MAGENTA);
601             BitmapWriteAccess write(bitmap);
602             if (write.HasPalette())
603             {
604                 // Note that SetPixel() and GetColor() take arguments as Y,X.
605                 write.SetPixel(0, 0, BitmapColor(write.GetBestPaletteIndex(COL_BLACK)));
606                 write.SetPixel(10, 0, BitmapColor(write.GetBestPaletteIndex(COL_WHITE)));
607                 write.SetPixel(0, 10, BitmapColor(write.GetBestPaletteIndex(COL_RED)));
608                 write.SetPixel(10, 10, BitmapColor(write.GetBestPaletteIndex(COL_BLUE)));
609                 write.SetPixel(5, 0, BitmapColor(write.GetBestPaletteIndex(COL_GREEN)));
610                 write.SetPixel(0, 5, BitmapColor(write.GetBestPaletteIndex(COL_YELLOW)));
611             }
612             else
613             {
614                 write.SetPixel(0, 0, COL_BLACK);
615                 write.SetPixel(10, 0, COL_WHITE);
616                 write.SetPixel(0, 10, COL_RED);
617                 write.SetPixel(10, 10, COL_BLUE);
618                 write.SetPixel(5, 0, COL_GREEN);
619                 write.SetPixel(0, 5, COL_YELLOW);
620             }
621         }
622         bitmap.Mirror(BmpMirrorFlags::Horizontal);
623         {
624             BitmapReadAccess read(bitmap);
625             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), read.GetColor(0, 10));
626             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), read.GetColor(10, 10));
627             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED), read.GetColor(0, 0));
628             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE), read.GetColor(10, 0));
629             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN), read.GetColor(5, 10));
630             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW), read.GetColor(0, 5));
631         }
632         bitmap.Mirror(BmpMirrorFlags::Vertical);
633         {
634             BitmapReadAccess read(bitmap);
635             // Now is effectively mirrored in both directions.
636             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), read.GetColor(10, 10));
637             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), read.GetColor(0, 10));
638             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED), read.GetColor(10, 0));
639             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE), read.GetColor(0, 0));
640             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN), read.GetColor(5, 10));
641             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW), read.GetColor(10, 5));
642         }
643         bitmap.Mirror(BmpMirrorFlags::Vertical | BmpMirrorFlags::Horizontal);
644         {
645             BitmapReadAccess read(bitmap);
646             // Now is back the original.
647             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), read.GetColor(0, 0));
648             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), read.GetColor(10, 0));
649             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED), read.GetColor(0, 10));
650             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLUE), read.GetColor(10, 10));
651             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_GREEN), read.GetColor(5, 0));
652             CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_YELLOW), read.GetColor(0, 5));
653         }
654     }
655 }
656 
testCroppedDownsampledBitmap()657 void BitmapTest::testCroppedDownsampledBitmap()
658 {
659     Bitmap aBitmap(Size(16, 16), vcl::PixelFormat::N24_BPP);
660     Bitmap aDownsampledBmp(vcl::bitmap::GetDownsampledBitmap(Size(10, 10), Point(20, 20),
661                                                              Size(5, 5), aBitmap, 72, 72));
662     CPPUNIT_ASSERT(aDownsampledBmp.IsEmpty());
663 }
664 
testCrop()665 void BitmapTest::testCrop()
666 {
667     Bitmap aBitmap(Bitmap(Size(16, 16), vcl::PixelFormat::N24_BPP));
668 
669     {
670         Bitmap aCroppedBmp(aBitmap);
671         CPPUNIT_ASSERT_MESSAGE("Crop was fully outside of bitmap bounds",
672                                !aCroppedBmp.Crop(tools::Rectangle(Point(20, 20), Size(5, 5))));
673         CPPUNIT_ASSERT_EQUAL(Size(16, 16), aCroppedBmp.GetSizePixel());
674     }
675 
676     {
677         Bitmap aCroppedBmp(aBitmap);
678         CPPUNIT_ASSERT_MESSAGE("Crop same size as bitmap",
679                                !aCroppedBmp.Crop(tools::Rectangle(Point(0, 0), Size(16, 16))));
680         CPPUNIT_ASSERT_EQUAL(Size(16, 16), aCroppedBmp.GetSizePixel());
681     }
682 
683     {
684         Bitmap aCroppedBmp(aBitmap);
685         CPPUNIT_ASSERT_MESSAGE("Crop larger than bitmap",
686                                !aCroppedBmp.Crop(tools::Rectangle(Point(0, 0), Size(100, 100))));
687         CPPUNIT_ASSERT_EQUAL(Size(16, 16), aCroppedBmp.GetSizePixel());
688     }
689 
690     {
691         Bitmap aCroppedBmp(aBitmap);
692         CPPUNIT_ASSERT_MESSAGE("Crop partially overcrops bitmap",
693                                aCroppedBmp.Crop(tools::Rectangle(Point(10, 10), Size(100, 100))));
694         CPPUNIT_ASSERT_EQUAL(Size(6, 6), aCroppedBmp.GetSizePixel());
695     }
696 
697     {
698         Bitmap aCroppedBmp(aBitmap);
699         CPPUNIT_ASSERT_MESSAGE("Crop inside bitmap",
700                                aCroppedBmp.Crop(tools::Rectangle(Point(5, 5), Size(10, 10))));
701         CPPUNIT_ASSERT_EQUAL(Size(10, 10), aCroppedBmp.GetSizePixel());
702     }
703 }
704 } // namespace
705 
706 CPPUNIT_TEST_SUITE_REGISTRATION(BitmapTest);
707 
708 CPPUNIT_PLUGIN_IMPLEMENT();
709 
710 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
711