diff --git a/tests/graphics/bitmap.cpp b/tests/graphics/bitmap.cpp index d3a7b60e07..0fbad0442c 100644 --- a/tests/graphics/bitmap.cpp +++ b/tests/graphics/bitmap.cpp @@ -30,6 +30,12 @@ CHECK( (int)g == (int)c.Green() ); \ CHECK( (int)b == (int)c.Blue() ) +#define ASSERT_EQUAL_RGBA(c, r, g, b, a) \ + CHECK( (int)r == (int)c.Red() ); \ + CHECK( (int)g == (int)c.Green() ); \ + CHECK( (int)b == (int)c.Blue() ); \ + CHECK( (int)a == (int)c.Alpha() ) + #ifdef __WXMSW__ // Support for iteration over 32 bpp 0RGB bitmaps typedef wxPixelFormat wxNative32PixelFormat; @@ -584,4 +590,329 @@ TEST_CASE("BitmapTestCase::DrawAlphaWithMask", "[bitmap][draw][alpha][withmask]" #endif // __WXMSW__ || __WXOSX__ } +TEST_CASE("BitmapTestCase::SubBitmapNonAlpha", "[bitmap][subbitmap][nonalpha]") +{ + const int w = 16; + const int h = 16; + + const wxColour clrTopLeft(*wxBLUE); + const wxColour clrTopRight(*wxRED); + const wxColour clrBottomLeft(*wxGREEN); + const wxColour clrBottomRight(*wxCYAN); + + // Bitmap + wxBitmap bmp(w, h, 24); + { + wxMemoryDC dc(bmp); + dc.SetPen(wxPen(clrTopLeft)); + dc.SetBrush(wxBrush(clrTopLeft)); + dc.DrawRectangle(0, 0, w / 2, h / 2); + dc.SetPen(wxPen(clrTopRight)); + dc.SetBrush(wxBrush(clrTopRight)); + dc.DrawRectangle(w / 2, 0, w / 2, h / 2); + dc.SetPen(wxPen(clrBottomLeft)); + dc.SetBrush(wxBrush(clrBottomLeft)); + dc.DrawRectangle(0, h / 2, w / 2, h / 2); + dc.SetPen(wxPen(clrBottomRight)); + dc.SetBrush(wxBrush(clrBottomRight)); + dc.DrawRectangle(w / 2, h / 2, w / 2, h / 2); + } + REQUIRE_FALSE(bmp.HasAlpha()); + REQUIRE(bmp.GetMask() == NULL); + + // Get sub bitmap + wxBitmap subBmp = bmp.GetSubBitmap(wxRect(w/4, h/4, w/2, h/2)); + // Check sub bitmap attributes + REQUIRE(subBmp.GetWidth() == w/2); + REQUIRE(subBmp.GetHeight() == h/2); + REQUIRE(subBmp.GetDepth() == bmp.GetDepth()); + REQUIRE(subBmp.HasAlpha() == bmp.HasAlpha()); + REQUIRE((subBmp.GetMask() == NULL) == (bmp.GetMask() == NULL)); + + const int w2 = w / 2; + const int h2 = h / 2; + // Check sub bitmap pixels + wxNativePixelData data(subBmp); + REQUIRE(data); + wxNativePixelData::Iterator p(data); + p.OffsetY(data, h2 / 4); + wxNativePixelData::Iterator rowStart = p; + p.OffsetX(data, w2 / 4); // top-left point + ASSERT_EQUAL_RGB(p, clrTopLeft.Red(), clrTopLeft.Green(), clrTopLeft.Blue()); + p.OffsetX(data, w2 / 2); // top-right point + ASSERT_EQUAL_RGB(p, clrTopRight.Red(), clrTopRight.Green(), clrTopRight.Blue()); + p = rowStart; + p.OffsetY(data, h2 / 2); + p.OffsetX(data, w2 / 4); // bottom-left point + ASSERT_EQUAL_RGB(p, clrBottomLeft.Red(), clrBottomLeft.Green(), clrBottomLeft.Blue()); + p.OffsetX(data, w2 / 2); // bottom-right point + ASSERT_EQUAL_RGB(p, clrBottomRight.Red(), clrBottomRight.Green(), clrBottomRight.Blue()); +} + +TEST_CASE("BitmapTestCase::SubBitmapNonAlphaWithMask", "[bitmap][subbitmap][nonalpha][withmask]") +{ + const int w = 16; + const int h = 16; + + // Mask + wxBitmap bmpMask = GetMask(w, h); + + const wxColour clrTopLeft(*wxBLUE); + const wxColour clrTopRight(*wxRED); + const wxColour clrBottomLeft(*wxGREEN); + const wxColour clrBottomRight(*wxCYAN); + + // Bitmap + wxBitmap bmp(w, h, 24); + { + wxMemoryDC dc(bmp); + dc.SetPen(wxPen(clrTopLeft)); + dc.SetBrush(wxBrush(clrTopLeft)); + dc.DrawRectangle(0, 0, w / 2, h / 2); + dc.SetPen(wxPen(clrTopRight)); + dc.SetBrush(wxBrush(clrTopRight)); + dc.DrawRectangle(w / 2, 0, w / 2, h / 2); + dc.SetPen(wxPen(clrBottomLeft)); + dc.SetBrush(wxBrush(clrBottomLeft)); + dc.DrawRectangle(0, h / 2, w / 2, h / 2); + dc.SetPen(wxPen(clrBottomRight)); + dc.SetBrush(wxBrush(clrBottomRight)); + dc.DrawRectangle(w / 2, h / 2, w / 2, h / 2); + } + REQUIRE_FALSE(bmp.HasAlpha()); + REQUIRE(bmp.GetMask() == NULL); + bmp.SetMask(new wxMask(bmpMask)); + REQUIRE_FALSE(bmp.HasAlpha()); + REQUIRE(bmp.GetMask() != NULL); + + // Get sub bitmap + wxBitmap subBmp = bmp.GetSubBitmap(wxRect(w/4, h/4, w/2, h/2)); + const int w2 = w / 2; + const int h2 = h / 2; + // Check sub bitmap attributes + REQUIRE(subBmp.GetWidth() == w2); + REQUIRE(subBmp.GetHeight() == h2); + REQUIRE(subBmp.GetDepth() == bmp.GetDepth()); + REQUIRE(subBmp.HasAlpha() == bmp.HasAlpha()); + REQUIRE((subBmp.GetMask() == NULL) == (bmp.GetMask() == NULL)); + + // Check sub bitmap pixels + { + wxNativePixelData data(subBmp); + REQUIRE(data); + wxNativePixelData::Iterator p(data); + p.OffsetY(data, h2 / 4); + wxNativePixelData::Iterator rowStart = p; + p.OffsetX(data, w2 / 4); // top-left point + ASSERT_EQUAL_RGB(p, clrTopLeft.Red(), clrTopLeft.Green(), clrTopLeft.Blue()); + p.OffsetX(data, w2 / 2); // top-right point + ASSERT_EQUAL_RGB(p, clrTopRight.Red(), clrTopRight.Green(), clrTopRight.Blue()); + p = rowStart; + p.OffsetY(data, h2 / 2); + p.OffsetX(data, w2 / 4); // bottom-left point + ASSERT_EQUAL_RGB(p, clrBottomLeft.Red(), clrBottomLeft.Green(), clrBottomLeft.Blue()); + p.OffsetX(data, w2 / 2); // bottom-right point + ASSERT_EQUAL_RGB(p, clrBottomRight.Red(), clrBottomRight.Green(), clrBottomRight.Blue()); + } + + // Check sub bitmap mask + wxColour maskClrTopLeft; + wxColour maskClrTopRight; + wxColour maskClrBottomLeft; + wxColour maskClrBottomRight; + // Fetch sample original mask pixels + { + wxNativePixelData data(bmpMask); + REQUIRE(data); + wxNativePixelData::Iterator p(data); + p.OffsetY(data, h / 4); + wxNativePixelData::Iterator rowStart = p; + p.OffsetX(data, w / 4); // top-left point + maskClrTopLeft = wxColour(p.Red(), p.Green(), p.Blue()); + p.OffsetX(data, w / 2); // top-right point + maskClrTopRight = wxColour(p.Red(), p.Green(), p.Blue()); + p = rowStart; + p.OffsetY(data, h / 2); + p.OffsetX(data, w / 4); // bottom-left point + maskClrBottomLeft = wxColour(p.Red(), p.Green(), p.Blue()); + p.OffsetX(data, w / 2); // bottom-right point + maskClrBottomRight = wxColour(p.Red(), p.Green(), p.Blue()); + } + CHECK(maskClrTopLeft == *wxWHITE); + CHECK(maskClrTopRight == *wxWHITE); + CHECK(maskClrBottomLeft == *wxBLACK); + CHECK(maskClrBottomRight == *wxBLACK); + + wxBitmap subBmpMask = subBmp.GetMask()->GetBitmap(); + // Check sub bitmap mask attributes + REQUIRE(subBmpMask.GetWidth() == subBmp.GetWidth()); + REQUIRE(subBmpMask.GetHeight() == subBmp.GetHeight()); +#if !defined(__WXOSX__) + REQUIRE(subBmpMask.GetDepth() == 1); +#endif // !__WXOSX__ + REQUIRE_FALSE(subBmpMask.HasAlpha()); + REQUIRE_FALSE(subBmpMask.GetMask()); + // Check sub bitmap mask pixels + { + wxNativePixelData data(subBmpMask); + REQUIRE(data); + wxNativePixelData::Iterator p(data); + p.OffsetY(data, h2 / 4); + wxNativePixelData::Iterator rowStart = p; + p.OffsetX(data, w2 / 4); // top-left point + ASSERT_EQUAL_RGB(p, maskClrTopLeft.Red(), maskClrTopLeft.Green(), maskClrTopLeft.Blue()); + p.OffsetX(data, w2 / 2); // top-right point + ASSERT_EQUAL_RGB(p, maskClrTopRight.Red(), maskClrTopRight.Green(), maskClrTopRight.Blue()); + p = rowStart; + p.OffsetY(data, h2 / 2); + p.OffsetX(data, w2 / 4); // bottom-left point + ASSERT_EQUAL_RGB(p, maskClrBottomLeft.Red(), maskClrBottomLeft.Green(), maskClrBottomLeft.Blue()); + p.OffsetX(data, w2 / 2); // bottom-right point + ASSERT_EQUAL_RGB(p, maskClrBottomRight.Red(), maskClrBottomRight.Green(), maskClrBottomRight.Blue()); + } +} + +TEST_CASE("BitmapTestCase::SubBitmapAlphaWithMask", "[bitmap][subbitmap][alpha][withmask]") +{ + const int w = 16; + const int h = 16; + + // Mask + wxBitmap bmpMask = GetMask(w, h); + + // Bitmap + const wxColour clrLeft(*wxCYAN); + const unsigned char alpha = 92; + +#if defined(__WXMSW__) || defined(__WXOSX__) + // premultiplied values + const wxColour clrRight(((clrLeft.Red() * alpha) + 127) / 255, ((clrLeft.Green() * alpha) + 127) / 255, ((clrLeft.Blue() * alpha) + 127) / 255, alpha); +#else + const wxColour clrRight(clrLeft.Red(), clrLeft.Green(), clrLeft.Blue(), alpha); +#endif // __WXMSW__ || __WXOSX__ + + wxBitmap bmp(w, h, 32); +#if defined(__WXMSW__) || defined(__WXOSX__) + bmp.UseAlpha(); +#endif // __WXMSW__ || __WXOSX__ + { + wxAlphaPixelData data(bmp); + REQUIRE(data); + wxAlphaPixelData::Iterator p(data); + for ( int y = 0; y < h; y++) + { + wxAlphaPixelData::Iterator rowStart = p; + for ( int x = 0; x < w; x++, ++p ) + { + if ( x < w / 2 ) + { // opaque + p.Red() = clrLeft.Red(); + p.Green() = clrLeft.Green(); + p.Blue() = clrLeft.Blue(); + p.Alpha() = clrLeft.Alpha(); + } + else + { // with transparency + p.Red() = clrRight.Red(); + p.Green() = clrRight.Green(); + p.Blue() = clrRight.Blue(); + p.Alpha() = clrRight.Alpha(); + } + } + p = rowStart; + p.OffsetY(data, 1); + } + } + REQUIRE(bmp.HasAlpha()); + REQUIRE(!bmp.GetMask()); + bmp.SetMask(new wxMask(bmpMask)); + REQUIRE(bmp.HasAlpha()); + REQUIRE(bmp.GetMask()); + + // Get sub bitmap + wxBitmap subBmp = bmp.GetSubBitmap(wxRect(w/4, h/4, w/2, h/2)); + const int w2 = w / 2; + const int h2 = h / 2; + // Check sub bitmap attributes + REQUIRE(subBmp.GetWidth() == w2); + REQUIRE(subBmp.GetHeight() == h2); + REQUIRE(subBmp.GetDepth() == bmp.GetDepth()); + REQUIRE(subBmp.HasAlpha() == bmp.HasAlpha()); + REQUIRE((subBmp.GetMask() == NULL) == (bmp.GetMask() == NULL)); + + // Check sub bitmap pixels + { + wxAlphaPixelData data(subBmp); + REQUIRE(data); + wxAlphaPixelData::Iterator p(data); + p.OffsetY(data, h2 / 4); + wxAlphaPixelData::Iterator rowStart = p; + p.OffsetX(data, w2 / 4); // top-left point + ASSERT_EQUAL_RGBA(p, clrLeft.Red(), clrLeft.Green(), clrLeft.Blue(), clrLeft.Alpha()); + p.OffsetX(data, w2 / 2); // top-right point + ASSERT_EQUAL_RGBA(p, clrRight.Red(), clrRight.Green(), clrRight.Blue(), clrRight.Alpha()); + p = rowStart; + p.OffsetY(data, h2 / 2); + p.OffsetX(data, w2 / 4); // bottom-left point + ASSERT_EQUAL_RGBA(p, clrLeft.Red(), clrLeft.Green(), clrLeft.Blue(), clrLeft.Alpha()); + p.OffsetX(data, w2 / 2); // bottom-right point + ASSERT_EQUAL_RGBA(p, clrRight.Red(), clrRight.Green(), clrRight.Blue(), clrRight.Alpha()); + } + + // Check sub bitmap mask + wxColour maskClrTopLeft; + wxColour maskClrTopRight; + wxColour maskClrBottomLeft; + wxColour maskClrBottomRight; + // Fetch sample original mask pixels + { + wxNativePixelData data(bmpMask); + REQUIRE(data); + wxNativePixelData::Iterator p(data); + p.OffsetY(data, h / 4); + wxNativePixelData::Iterator rowStart = p; + p.OffsetX(data, w / 4); // top-left point + maskClrTopLeft = wxColour(p.Red(), p.Green(), p.Blue()); + p.OffsetX(data, w / 2); // top-right point + maskClrTopRight = wxColour(p.Red(), p.Green(), p.Blue()); + p = rowStart; + p.OffsetY(data, h / 2); + p.OffsetX(data, w / 4); // bottom-left point + maskClrBottomLeft = wxColour(p.Red(), p.Green(), p.Blue()); + p.OffsetX(data, w / 2); // bottom-right point + maskClrBottomRight = wxColour(p.Red(), p.Green(), p.Blue()); + } + CHECK(maskClrTopLeft == *wxWHITE); + CHECK(maskClrTopRight == *wxWHITE); + CHECK(maskClrBottomLeft == *wxBLACK); + CHECK(maskClrBottomRight == *wxBLACK); + + wxBitmap subBmpMask = subBmp.GetMask()->GetBitmap(); + // Check sub bitmap mask attributes + REQUIRE(subBmpMask.GetWidth() == subBmp.GetWidth()); + REQUIRE(subBmpMask.GetHeight() == subBmp.GetHeight()); +#if !defined(__WXOSX__) + REQUIRE(subBmpMask.GetDepth() == 1); +#endif // !__WXOSX__ + REQUIRE_FALSE(subBmpMask.HasAlpha()); + REQUIRE_FALSE(subBmpMask.GetMask()); + // Check sub bitmap mask pixels + { + wxNativePixelData data(subBmpMask); + REQUIRE(data); + wxNativePixelData::Iterator p(data); + p.OffsetY(data, h2 / 4); + wxNativePixelData::Iterator rowStart = p; + p.OffsetX(data, w2 / 4); // top-left point + ASSERT_EQUAL_RGB(p, maskClrTopLeft.Red(), maskClrTopLeft.Green(), maskClrTopLeft.Blue()); + p.OffsetX(data, w2 / 2); // top-right point + ASSERT_EQUAL_RGB(p, maskClrTopRight.Red(), maskClrTopRight.Green(), maskClrTopRight.Blue()); + p = rowStart; + p.OffsetY(data, h2 / 2); + p.OffsetX(data, w2 / 4); // bottom-left point + ASSERT_EQUAL_RGB(p, maskClrBottomLeft.Red(), maskClrBottomLeft.Green(), maskClrBottomLeft.Blue()); + p.OffsetX(data, w2 / 2); // bottom-right point + ASSERT_EQUAL_RGB(p, maskClrBottomRight.Red(), maskClrBottomRight.Green(), maskClrBottomRight.Blue()); + } +} #endif //wxHAS_RAW_BITMAP