wxWidgets/tests/graphics/bitmap.cpp
Vadim Zeitlin 24970061fa Add wxBitmap(wxImage, wxDC) ctor to all ports
This ctor was previously present only in wxMSW, make it available in all
ports to allow the same code to compile everywhere.

In most of them wxDC argument is simply ignored, but in wxGTK and wxOSX
it is used to assign the appropriate scale factor for the new bitmap.

Enable previously wxMSW-only unit test checking for this.
2022-04-12 19:08:56 +01:00

1830 lines
63 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: tests/graphics/bitmap.cpp
// Purpose: wxBitmap unit test
// Author: Vadim Zeitlin
// Created: 2010-03-29
// Copyright: (c) 2010 Vadim Zeitlin <vadim@wxwidgets.org>
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifdef wxHAS_RAW_BITMAP
#include "wx/bitmap.h"
#include "wx/rawbmp.h"
#include "wx/dcmemory.h"
#include "wx/dcsvg.h"
#if wxUSE_GRAPHICS_CONTEXT
#include "wx/graphics.h"
#endif // wxUSE_GRAPHICS_CONTEXT
#include "testfile.h"
#include "testimage.h"
#define ASSERT_EQUAL_RGB(c, r, g, b) \
CHECK( (int)r == (int)c.Red() ); \
CHECK( (int)g == (int)c.Green() ); \
CHECK( (int)b == (int)c.Blue() )
#define ASSERT_EQUAL_COLOUR_RGB(c1, c2) \
CHECK( (int)c1.Red() == (int)c2.Red() ); \
CHECK( (int)c1.Green() == (int)c2.Green() ); \
CHECK( (int)c1.Blue() == (int)c2.Blue() )
#define ASSERT_EQUAL_COLOUR_RGBA(c1, c2) \
CHECK( (int)c1.Red() == (int)c2.Red() ); \
CHECK( (int)c1.Green() == (int)c2.Green() ); \
CHECK( (int)c1.Blue() == (int)c2.Blue() ); \
CHECK( (int)c1.Alpha() == (int)c2.Alpha() )
#define CHECK_EQUAL_COLOUR_RGB(c1, c2) ASSERT_EQUAL_COLOUR_RGB(c1, c2)
#define CHECK_EQUAL_COLOUR_RGBA(c1, c2) ASSERT_EQUAL_COLOUR_RGBA(c1, c2)
#ifdef __WXMSW__
// Support for iteration over 32 bpp 0RGB bitmaps
typedef wxPixelFormat<unsigned char, 32, 2, 1, 0> wxNative32PixelFormat;
typedef wxPixelData<wxBitmap, wxNative32PixelFormat> wxNative32PixelData;
#endif // __WXMSW__
#ifdef __WXOSX__
// 32 bpp xRGB bitmaps are native ones
typedef wxNativePixelData wxNative32PixelData;
#endif // __WXOSX__
// ----------------------------------------------------------------------------
// tests
// ----------------------------------------------------------------------------
TEST_CASE("BitmapTestCase::Monochrome", "[bitmap][monochrome]")
{
#ifdef __WXGTK__
WARN("Skipping test known not to work in wxGTK.");
#elif defined(__WXOSX__)
WARN("Skipping test known not to work in wxOSX.");
#else
wxBitmap color;
color.LoadFile("horse.bmp", wxBITMAP_TYPE_BMP);
REQUIRE(color.IsOk());
REQUIRE(color.GetDepth() == 32);
wxImage imgQuant = color.ConvertToImage();
wxBitmap bmpQuant(imgQuant, 1);
REQUIRE(bmpQuant.GetDepth() == 1);
TempFile mono_horse("mono_horse.bmp");
REQUIRE(bmpQuant.SaveFile(mono_horse.GetName(), wxBITMAP_TYPE_BMP));
wxBitmap mono;
REQUIRE(mono.LoadFile(mono_horse.GetName(), wxBITMAP_TYPE_BMP));
REQUIRE(mono.IsOk());
REQUIRE(mono.GetDepth() == 1);
// wxMonoPixelData only exists in wxMSW
#if defined(__WXMSW__)
// draw lines on top and left, but leaving blank top and left lines
{
wxMonoPixelData data(mono);
wxMonoPixelData::Iterator p(data);
p.OffsetY(data, 1);
for ( int i = 0; i < data.GetWidth() - 2; ++i )
{
++p;
p.Pixel() = 0;
}
p.MoveTo(data, 1, 1);
for ( int i = 0; i < data.GetHeight() - 3; ++i )
{
p.OffsetY(data, 1);
p.Pixel() = 1;
}
}
TempFile mono_lines_horse("mono_lines_horse.bmp");
REQUIRE(mono.SaveFile(mono_lines_horse.GetName(), wxBITMAP_TYPE_BMP));
#endif // __WXMSW__
#endif // !__WXGTK__
}
TEST_CASE("BitmapTestCase::Mask", "[bitmap][mask]")
{
wxBitmap bmp(10, 10);
{
wxMemoryDC dc(bmp);
dc.SetBackground(*wxWHITE);
dc.Clear();
dc.SetBrush(*wxBLACK_BRUSH);
dc.DrawRectangle(4, 4, 2, 2);
dc.SetPen(*wxRED_PEN);
dc.DrawLine(0, 0, 10, 10);
dc.DrawLine(10, 0, 0, 10);
}
wxMask *mask = new wxMask(bmp, *wxBLACK);
bmp.SetMask(mask);
REQUIRE(bmp.GetMask() == mask);
// copying masks should work
wxMask *mask2 = NULL;
REQUIRE_NOTHROW(mask2 = new wxMask(*mask));
bmp.SetMask(mask2);
REQUIRE(bmp.GetMask() == mask2);
}
TEST_CASE("BitmapTestCase::ToImage", "[bitmap][image][convertto]")
{
SECTION("RGB bitmap without mask")
{
// RGB bitmap
wxBitmap bmp(16, 16, 24);
{
wxMemoryDC dc(bmp);
dc.SetPen(*wxYELLOW_PEN);
dc.SetBrush(*wxYELLOW_BRUSH);
dc.DrawRectangle(0, 0, bmp.GetWidth(), bmp.GetHeight());
}
REQUIRE_FALSE(bmp.HasAlpha());
REQUIRE(bmp.GetMask() == NULL);
wxImage image = bmp.ConvertToImage();
REQUIRE_FALSE(image.HasAlpha());
REQUIRE_FALSE(image.HasMask());
REQUIRE(image.GetWidth() == bmp.GetWidth());
REQUIRE(image.GetHeight() == bmp.GetHeight());
wxNativePixelData dataBmp(bmp);
wxNativePixelData::Iterator rowStartBmp(dataBmp);
for ( int y = 0; y < bmp.GetHeight(); ++y )
{
wxNativePixelData::Iterator iBmp = rowStartBmp;
for ( int x = 0; x < bmp.GetWidth(); ++x, ++iBmp )
{
wxColour bmpc(iBmp.Red(), iBmp.Green(), iBmp.Blue());
wxColour imgc(image.GetRed(x, y), image.GetGreen(x, y), image.GetBlue(x, y));
CHECK_EQUAL_COLOUR_RGB(imgc, bmpc);
}
rowStartBmp.OffsetY(dataBmp, 1);
}
}
SECTION("RGB bitmap with mask")
{
// RGB bitmap
wxBitmap bmp(16, 16, 24);
{
wxMemoryDC dc(bmp);
dc.SetPen(*wxYELLOW_PEN);
dc.SetBrush(*wxYELLOW_BRUSH);
dc.DrawRectangle(0, 0, bmp.GetWidth(), bmp.GetHeight());
}
// Mask
wxBitmap bmask(bmp.GetWidth(), bmp.GetHeight(), 1);
{
wxMemoryDC dc(bmask);
#if wxUSE_GRAPHICS_CONTEXT
wxGraphicsContext* gc = dc.GetGraphicsContext();
if (gc)
{
gc->SetAntialiasMode(wxANTIALIAS_NONE);
}
#endif // wxUSE_GRAPHICS_CONTEXT
dc.SetBackground(*wxBLACK_BRUSH);
dc.Clear();
dc.SetPen(*wxWHITE_PEN);
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle(4, 4, 8, 8);
}
bmp.SetMask(new wxMask(bmask));
REQUIRE_FALSE(bmp.HasAlpha());
REQUIRE(bmp.GetMask() != NULL);
const int numUnmaskedPixels = 8 * 8;
wxImage image = bmp.ConvertToImage();
REQUIRE_FALSE(image.HasAlpha());
REQUIRE(image.HasMask() == true);
REQUIRE(image.GetWidth() == bmp.GetWidth());
REQUIRE(image.GetHeight() == bmp.GetHeight());
const wxColour maskCol(image.GetMaskRed(), image.GetMaskGreen(), image.GetMaskBlue());
REQUIRE(maskCol.IsOk());
wxNativePixelData dataBmp(bmp);
wxNativePixelData::Iterator rowStartBmp(dataBmp);
wxBitmap mask = bmp.GetMask()->GetBitmap();
wxNativePixelData dataMask(mask);
wxNativePixelData::Iterator rowStartMask(dataMask);
int unmaskedPixelsCount = 0;
for ( int y = 0; y < bmp.GetHeight(); ++y )
{
wxNativePixelData::Iterator iBmp = rowStartBmp;
wxNativePixelData::Iterator iMask = rowStartMask;
for ( int x = 0; x < bmp.GetWidth(); ++x, ++iBmp, ++iMask )
{
wxColour bmpc(iBmp.Red(), iBmp.Green(), iBmp.Blue());
wxColour maskc(iMask.Red(), iMask.Green(), iMask.Blue());
wxColour imgc(image.GetRed(x, y), image.GetGreen(x, y), image.GetBlue(x, y));
if ( maskc == *wxWHITE )
{
CHECK_EQUAL_COLOUR_RGB(imgc, bmpc);
unmaskedPixelsCount++;
}
else
{
CHECK_EQUAL_COLOUR_RGB(imgc, maskCol);
}
}
rowStartBmp.OffsetY(dataBmp, 1);
rowStartMask.OffsetY(dataMask, 1);
}
CHECK(unmaskedPixelsCount == numUnmaskedPixels);
}
SECTION("RGBA bitmap without mask")
{
// RGBA Bitmap
wxBitmap bmp(16, 16, 32);
#if defined(__WXMSW__) || defined(__WXOSX__)
bmp.UseAlpha();
#endif // __WXMSW__ || __WXOSX__
{
const wxColour clrFg(*wxCYAN);
const wxColour clrBg(*wxGREEN);
const unsigned char alpha = 92;
#if defined(__WXMSW__) || defined(__WXOSX__)
// premultiplied values
const wxColour clrFgAlpha(((clrFg.Red() * alpha) + 127) / 255, ((clrFg.Green() * alpha) + 127) / 255, ((clrFg.Blue() * alpha) + 127) / 255);
#else
const wxColour clrFgAlpha(clrFg);
#endif // __WXMSW__ || __WXOSX__
wxAlphaPixelData data(bmp);
REQUIRE(data);
wxAlphaPixelData::Iterator p(data);
for ( int y = 0; y < bmp.GetHeight(); y++)
{
wxAlphaPixelData::Iterator rowStart = p;
for ( int x = 0; x < bmp.GetWidth(); x++, ++p )
{
if ( x < bmp.GetWidth() / 2 )
{ // opaque
p.Red() = clrFg.Red();
p.Green() = clrFg.Green();
p.Blue() = clrFg.Blue();
p.Alpha() = 255;
}
else
{ // with transparency
p.Red() = clrFgAlpha.Red();
p.Green() = clrFgAlpha.Green();
p.Blue() = clrFgAlpha.Blue();
p.Alpha() = alpha;
}
}
p = rowStart;
p.OffsetY(data, 1);
}
}
REQUIRE(bmp.HasAlpha() == true);
REQUIRE(bmp.GetMask() == NULL);
wxImage image = bmp.ConvertToImage();
REQUIRE(image.HasAlpha() == true);
REQUIRE_FALSE(image.HasMask());
REQUIRE(image.GetWidth() == bmp.GetWidth());
REQUIRE(image.GetHeight() == bmp.GetHeight());
wxAlphaPixelData dataBmp(bmp);
wxAlphaPixelData::Iterator rowStartBmp(dataBmp);
for ( int y = 0; y < bmp.GetHeight(); ++y )
{
wxAlphaPixelData::Iterator iBmp = rowStartBmp;
for ( int x = 0; x < bmp.GetWidth(); ++x, ++iBmp )
{
wxColour bmpc(iBmp.Red(), iBmp.Green(), iBmp.Blue(), iBmp.Alpha());
wxColour imgc(image.GetRed(x, y), image.GetGreen(x, y), image.GetBlue(x, y), image.GetAlpha(x,y));
#if defined(__WXMSW__) || defined(__WXOSX__)
// Premultiplied values
unsigned char r = ((imgc.Red() * imgc.Alpha()) + 127) / 255;
unsigned char g = ((imgc.Green() * imgc.Alpha()) + 127) / 255;
unsigned char b = ((imgc.Blue() * imgc.Alpha()) + 127) / 255;
imgc.Set(r, g, b, imgc.Alpha());
#endif // __WXMSW__ || __WXOSX__
CHECK_EQUAL_COLOUR_RGBA(imgc, bmpc);
}
rowStartBmp.OffsetY(dataBmp, 1);
}
}
SECTION("RGBA bitmap with mask")
{
// RGBA Bitmap
wxBitmap bmp(16, 16, 32);
#if defined(__WXMSW__) || defined(__WXOSX__)
bmp.UseAlpha();
#endif // __WXMSW__ || __WXOSX__
{
const wxColour clrFg(*wxCYAN);
const wxColour clrBg(*wxGREEN);
const unsigned char alpha = 92;
#if defined(__WXMSW__) || defined(__WXOSX__)
// premultiplied values
const wxColour clrFgAlpha(((clrFg.Red() * alpha) + 127) / 255, ((clrFg.Green() * alpha) + 127) / 255, ((clrFg.Blue() * alpha) + 127) / 255);
#else
const wxColour clrFgAlpha(clrFg);
#endif // __WXMSW__ || __WXOSX__
wxAlphaPixelData data(bmp);
REQUIRE(data);
wxAlphaPixelData::Iterator p(data);
for ( int y = 0; y < bmp.GetHeight(); y++)
{
wxAlphaPixelData::Iterator rowStart = p;
for ( int x = 0; x < bmp.GetWidth(); x++, ++p )
{
if ( x < bmp.GetWidth() / 2 )
{ // opaque
p.Red() = clrFg.Red();
p.Green() = clrFg.Green();
p.Blue() = clrFg.Blue();
p.Alpha() = 255;
}
else
{ // with transparency
p.Red() = clrFgAlpha.Red();
p.Green() = clrFgAlpha.Green();
p.Blue() = clrFgAlpha.Blue();
p.Alpha() = alpha;
}
}
p = rowStart;
p.OffsetY(data, 1);
}
}
// Mask
wxBitmap bmask(bmp.GetWidth(), bmp.GetHeight(), 1);
{
wxMemoryDC dc(bmask);
#if wxUSE_GRAPHICS_CONTEXT
wxGraphicsContext* gc = dc.GetGraphicsContext();
if (gc)
{
gc->SetAntialiasMode(wxANTIALIAS_NONE);
}
#endif // wxUSE_GRAPHICS_CONTEXT
dc.SetBackground(*wxBLACK_BRUSH);
dc.Clear();
dc.SetPen(*wxWHITE_PEN);
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle(4, 4, 8, 8);
}
bmp.SetMask(new wxMask(bmask));
REQUIRE(bmp.HasAlpha() == true);
REQUIRE(bmp.GetMask() != NULL);
const int numUnmaskedPixels = 8 * 8;
wxImage image = bmp.ConvertToImage();
REQUIRE(image.HasAlpha() == true);
REQUIRE(image.HasMask() == true);
REQUIRE(image.GetWidth() == bmp.GetWidth());
REQUIRE(image.GetHeight() == bmp.GetHeight());
const wxColour maskCol(image.GetMaskRed(), image.GetMaskGreen(), image.GetMaskBlue());
REQUIRE(maskCol.IsOk());
wxAlphaPixelData dataBmp(bmp);
wxAlphaPixelData::Iterator rowStartBmp(dataBmp);
wxBitmap mask = bmp.GetMask()->GetBitmap();
wxNativePixelData dataMask(mask);
wxNativePixelData::Iterator rowStartMask(dataMask);
int unmaskedPixelsCount = 0;
for ( int y = 0; y < bmp.GetHeight(); ++y )
{
wxAlphaPixelData::Iterator iBmp = rowStartBmp;
wxNativePixelData::Iterator iMask = rowStartMask;
for ( int x = 0; x < bmp.GetWidth(); ++x, ++iBmp, ++iMask )
{
wxColour bmpc(iBmp.Red(), iBmp.Green(), iBmp.Blue(), iBmp.Alpha());
wxColour maskc(iMask.Red(), iMask.Green(), iMask.Blue());
wxColour imgc(image.GetRed(x, y), image.GetGreen(x, y), image.GetBlue(x, y), image.GetAlpha(x,y));
if ( maskc == *wxWHITE )
{
#if defined(__WXMSW__) || defined(__WXOSX__)
// Premultiplied values
unsigned char r = ((imgc.Red() * imgc.Alpha()) + 127) / 255;
unsigned char g = ((imgc.Green() * imgc.Alpha()) + 127) / 255;
unsigned char b = ((imgc.Blue() * imgc.Alpha()) + 127) / 255;
imgc.Set(r, g, b, imgc.Alpha());
#endif // __WXMSW__ || __WXOSX
CHECK_EQUAL_COLOUR_RGBA(imgc, bmpc);
unmaskedPixelsCount++;
}
else
{
CHECK_EQUAL_COLOUR_RGB(imgc, maskCol);
CHECK(imgc.Alpha() == bmpc.Alpha());
}
}
rowStartBmp.OffsetY(dataBmp, 1);
rowStartMask.OffsetY(dataMask, 1);
}
CHECK(unmaskedPixelsCount == numUnmaskedPixels);
}
}
TEST_CASE("BitmapTestCase::FromImage", "[bitmap][image][convertfrom]")
{
const wxColour maskCol(*wxRED);
const wxColour fillCol(*wxGREEN);
SECTION("RGB image without mask")
{
wxImage img(2, 2);
img.SetRGB(0, 0, maskCol.Red(), maskCol.Green(), maskCol.Blue());
img.SetRGB(0, 1, maskCol.Red(), maskCol.Green(), maskCol.Blue());
img.SetRGB(1, 0, fillCol.Red(), fillCol.Green(), fillCol.Blue());
img.SetRGB(1, 1, fillCol.Red(), fillCol.Green(), fillCol.Blue());
REQUIRE_FALSE(img.HasAlpha());
REQUIRE_FALSE(img.HasMask());
wxBitmap bmp(img);
REQUIRE_FALSE(bmp.HasAlpha());
REQUIRE(bmp.GetMask() == NULL);
REQUIRE(bmp.GetWidth() == img.GetWidth());
REQUIRE(bmp.GetHeight() == img.GetHeight());
wxNativePixelData dataBmp(bmp);
wxNativePixelData::Iterator rowStartBmp(dataBmp);
for ( int y = 0; y < bmp.GetHeight(); ++y )
{
wxNativePixelData::Iterator iBmp = rowStartBmp;
for ( int x = 0; x < bmp.GetWidth(); ++x, ++iBmp )
{
wxColour bmpc(iBmp.Red(), iBmp.Green(), iBmp.Blue());
wxColour imgc(img.GetRed(x, y), img.GetGreen(x, y), img.GetBlue(x, y));
CHECK_EQUAL_COLOUR_RGB(bmpc, imgc);
}
rowStartBmp.OffsetY(dataBmp, 1);
}
}
SECTION("RGB image with mask")
{
wxImage img(2, 2);
img.SetRGB(0, 0, maskCol.Red(), maskCol.Green(), maskCol.Blue());
img.SetRGB(0, 1, maskCol.Red(), maskCol.Green(), maskCol.Blue());
img.SetRGB(1, 0, fillCol.Red(), fillCol.Green(), fillCol.Blue());
img.SetRGB(1, 1, fillCol.Red(), fillCol.Green(), fillCol.Blue());
img.SetMaskColour(maskCol.Red(), maskCol.Green(), maskCol.Blue());
REQUIRE_FALSE(img.HasAlpha());
REQUIRE(img.HasMask() == true);
wxBitmap bmp(img);
REQUIRE_FALSE(bmp.HasAlpha());
REQUIRE(bmp.GetMask() != NULL);
REQUIRE(bmp.GetWidth() == img.GetWidth());
REQUIRE(bmp.GetHeight() == img.GetHeight());
wxNativePixelData dataBmp(bmp);
wxNativePixelData::Iterator rowStartBmp(dataBmp);
wxBitmap mask = bmp.GetMask()->GetBitmap();
wxNativePixelData dataMask(mask);
wxNativePixelData::Iterator rowStartMask(dataMask);
for ( int y = 0; y < bmp.GetHeight(); ++y )
{
wxNativePixelData::Iterator iBmp = rowStartBmp;
wxNativePixelData::Iterator iMask = rowStartMask;
for ( int x = 0; x < bmp.GetWidth(); ++x, ++iBmp, ++iMask )
{
wxColour bmpc(iBmp.Red(), iBmp.Green(), iBmp.Blue());
wxColour maskc(iMask.Red(), iMask.Green(), iMask.Blue());
wxColour imgc(img.GetRed(x, y), img.GetGreen(x, y), img.GetBlue(x, y));
CHECK_EQUAL_COLOUR_RGB(bmpc, imgc);
wxColour c = maskc == *wxWHITE ? fillCol : maskCol;
CHECK_EQUAL_COLOUR_RGB(bmpc, c);
}
rowStartBmp.OffsetY(dataBmp, 1);
rowStartMask.OffsetY(dataMask, 1);
}
}
SECTION("RGBA image without mask")
{
wxImage img(2, 2);
img.SetRGB(0, 0, maskCol.Red(), maskCol.Green(), maskCol.Blue());
img.SetRGB(0, 1, maskCol.Red(), maskCol.Green(), maskCol.Blue());
img.SetRGB(1, 0, fillCol.Red(), fillCol.Green(), fillCol.Blue());
img.SetRGB(1, 1, fillCol.Red(), fillCol.Green(), fillCol.Blue());
img.SetAlpha();
img.SetAlpha(0, 0, 128);
img.SetAlpha(0, 1, 0);
img.SetAlpha(1, 0, 128);
img.SetAlpha(1, 1, 0);
REQUIRE(img.HasAlpha() == true);
REQUIRE_FALSE(img.HasMask());
wxBitmap bmp(img);
REQUIRE(bmp.HasAlpha() == true);
REQUIRE(bmp.GetMask() == NULL);
REQUIRE(bmp.GetWidth() == img.GetWidth());
REQUIRE(bmp.GetHeight() == img.GetHeight());
wxAlphaPixelData dataBmp(bmp);
wxAlphaPixelData::Iterator rowStartBmp(dataBmp);
for ( int y = 0; y < bmp.GetHeight(); ++y )
{
wxAlphaPixelData::Iterator iBmp = rowStartBmp;
for ( int x = 0; x < bmp.GetWidth(); ++x, ++iBmp )
{
wxColour bmpc(iBmp.Red(), iBmp.Green(), iBmp.Blue(), iBmp.Alpha());
wxColour imgc(img.GetRed(x, y), img.GetGreen(x, y), img.GetBlue(x, y), img.GetAlpha(x, y));
#if defined(__WXMSW__) || defined(__WXOSX__)
// Premultiplied values
unsigned char r = ((imgc.Red() * imgc.Alpha()) + 127) / 255;
unsigned char g = ((imgc.Green() * imgc.Alpha()) + 127) / 255;
unsigned char b = ((imgc.Blue() * imgc.Alpha()) + 127) / 255;
imgc.Set(r, g, b, imgc.Alpha());
#endif // __WXMSW__ || __WXOSX__
CHECK_EQUAL_COLOUR_RGBA(bmpc, imgc);
}
rowStartBmp.OffsetY(dataBmp, 1);
}
}
SECTION("RGBA image with mask")
{
wxImage img(2, 2);
img.SetRGB(0, 0, maskCol.Red(), maskCol.Green(), maskCol.Blue());
img.SetRGB(0, 1, maskCol.Red(), maskCol.Green(), maskCol.Blue());
img.SetRGB(1, 0, fillCol.Red(), fillCol.Green(), fillCol.Blue());
img.SetRGB(1, 1, fillCol.Red(), fillCol.Green(), fillCol.Blue());
img.SetAlpha();
img.SetAlpha(0, 0, 128);
img.SetAlpha(0, 1, 0);
img.SetAlpha(1, 0, 128);
img.SetAlpha(1, 1, 0);
img.SetMaskColour(maskCol.Red(), maskCol.Green(), maskCol.Blue());
REQUIRE(img.HasAlpha() == true);
REQUIRE(img.HasMask() == true);
wxBitmap bmp(img);
REQUIRE(bmp.HasAlpha() == true);
REQUIRE(bmp.GetMask() != NULL);
REQUIRE(bmp.GetWidth() == img.GetWidth());
REQUIRE(bmp.GetHeight() == img.GetHeight());
wxAlphaPixelData dataBmp(bmp);
wxAlphaPixelData::Iterator rowStartBmp(dataBmp);
wxBitmap mask = bmp.GetMask()->GetBitmap();
wxNativePixelData dataMask(mask);
wxNativePixelData::Iterator rowStartMask(dataMask);
for ( int y = 0; y < bmp.GetHeight(); ++y )
{
wxAlphaPixelData::Iterator iBmp = rowStartBmp;
wxNativePixelData::Iterator iMask = rowStartMask;
for ( int x = 0; x < bmp.GetWidth(); ++x, ++iBmp, ++iMask )
{
wxColour bmpc(iBmp.Red(), iBmp.Green(), iBmp.Blue(), iBmp.Alpha());
wxColour maskc(iMask.Red(), iMask.Green(), iMask.Blue());
wxColour imgc(img.GetRed(x, y), img.GetGreen(x, y), img.GetBlue(x, y), img.GetAlpha(x, y));
#if defined(__WXMSW__) || defined(__WXOSX__)
// Premultiplied values
unsigned char r = ((imgc.Red() * imgc.Alpha()) + 127) / 255;
unsigned char g = ((imgc.Green() * imgc.Alpha()) + 127) / 255;
unsigned char b = ((imgc.Blue() * imgc.Alpha()) + 127) / 255;
imgc.Set(r, g, b, imgc.Alpha());
#endif // __WXMSW__ || __WXOSX__
CHECK_EQUAL_COLOUR_RGBA(bmpc, imgc);
wxColour c = maskc == *wxWHITE ? fillCol : maskCol;
#if defined(__WXMSW__) || defined(__WXOSX__)
// Premultiplied values
r = ((c.Red() * imgc.Alpha()) + 127) / 255;
g = ((c.Green() * imgc.Alpha()) + 127) / 255;
b = ((c.Blue() * imgc.Alpha()) + 127) / 255;
c.Set(r, g, b);
#endif // __WXMSW__ || __WXOSX__
CHECK_EQUAL_COLOUR_RGB(bmpc, c);
}
rowStartBmp.OffsetY(dataBmp, 1);
rowStartMask.OffsetY(dataMask, 1);
}
}
}
TEST_CASE("BitmapTestCase::OverlappingBlit", "[bitmap][blit]")
{
wxBitmap bmp(10, 10);
{
wxMemoryDC dc(bmp);
dc.SetBackground(*wxWHITE);
dc.Clear();
dc.SetBrush(*wxBLACK_BRUSH);
dc.DrawRectangle(4, 4, 2, 2);
dc.SetPen(*wxRED_PEN);
dc.DrawLine(0, 0, 10, 10);
dc.DrawLine(10, 0, 0, 10);
}
REQUIRE(bmp.GetMask() == NULL);
// Clear to white.
{
wxMemoryDC dc(bmp);
#if wxUSE_GRAPHICS_CONTEXT
wxGraphicsContext* gc = dc.GetGraphicsContext();
if ( gc )
{
gc->SetAntialiasMode(wxANTIALIAS_NONE);
}
#endif // wxUSE_GRAPHICS_CONTEXT
dc.SetBackground( *wxWHITE );
dc.Clear();
// Draw red line across the top.
dc.SetPen(*wxRED_PEN);
dc.DrawLine(0, 0, 10, 0);
// Scroll down one line.
dc.Blit( 0, 1, 10, 9, &dc, 0, 0 );
} // Select the bitmap out of the memory DC before using it directly.
// Now, lines 0 and 1 should be red, lines 2++ should still be white.
if ( bmp.GetDepth() == 32 )
{
wxAlphaPixelData npd( bmp );
REQUIRE( npd );
wxAlphaPixelData::Iterator it( npd );
ASSERT_EQUAL_RGB( it, 255, 0, 0 );
it.OffsetY( npd, 1 );
ASSERT_EQUAL_RGB( it, 255, 0, 0 );
it.OffsetY( npd, 1 );
ASSERT_EQUAL_RGB( it, 255, 255, 255 );
it.OffsetY( npd, 1 );
ASSERT_EQUAL_RGB( it, 255, 255, 255 );
}
else
{
wxNativePixelData npd( bmp );
REQUIRE( npd );
wxNativePixelData::Iterator it( npd );
ASSERT_EQUAL_RGB( it, 255, 0, 0 );
it.OffsetY( npd, 1 );
ASSERT_EQUAL_RGB( it, 255, 0, 0 );
it.OffsetY( npd, 1 );
ASSERT_EQUAL_RGB( it, 255, 255, 255 );
it.OffsetY( npd, 1 );
ASSERT_EQUAL_RGB( it, 255, 255, 255 );
}
}
static wxBitmap GetMask(int w, int h)
{
wxBitmap bmask(w, h, 1);
{
wxMemoryDC dc(bmask);
#if wxUSE_GRAPHICS_CONTEXT
wxGraphicsContext* gc = dc.GetGraphicsContext();
if ( gc )
{
gc->SetAntialiasMode(wxANTIALIAS_NONE);
}
#endif // wxUSE_GRAPHICS_CONTEXT
dc.SetBackground(*wxBLACK_BRUSH);
dc.Clear();
dc.SetPen(*wxWHITE_PEN);
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle(0, 0, w, h / 2);
}
return bmask;
}
TEST_CASE("BitmapTestCase::DrawNonAlphaWithMask", "[bitmap][draw][nonalpha][withmask]")
{
const int w = 16;
const int h = 16;
// Mask
wxBitmap bmask = GetMask(w, h);
const wxColour clrLeft(*wxBLUE);
const wxColour clrRight(*wxRED);
const wxColour clrBg(*wxCYAN);
// Bitmap with mask to be drawn
wxBitmap bmp(w, h, 24);
{
wxMemoryDC dc(bmp);
dc.SetPen(wxPen(clrLeft));
dc.SetBrush(wxBrush(clrLeft));
dc.DrawRectangle(0, 0, w / 2, h);
dc.SetPen(wxPen(clrRight));
dc.SetBrush(wxBrush(clrRight));
dc.DrawRectangle(w / 2, 0, w / 2, h);
}
REQUIRE_FALSE(bmp.HasAlpha());
REQUIRE(bmp.GetMask() == NULL);
bmp.SetMask(new wxMask(bmask));
REQUIRE_FALSE(bmp.HasAlpha());
REQUIRE(bmp.GetMask() != NULL);
// Drawing the bitmap using mask
{
wxBitmap bmpOut(w, h, 24);
{
wxMemoryDC dc(bmpOut);
dc.SetBackground(wxBrush(clrBg));
dc.Clear();
dc.DrawBitmap(bmp, wxPoint(0, 0), true);
}
// Check pixels
wxNativePixelData data(bmpOut);
REQUIRE(data);
wxNativePixelData::Iterator p(data);
p.OffsetY(data, h / 4);
wxNativePixelData::Iterator rowStart = p;
p.OffsetX(data, w / 4); // drawn area - left side
ASSERT_EQUAL_COLOUR_RGB(p, clrLeft);
p.OffsetX(data, w / 2); // drawn area - right side
ASSERT_EQUAL_COLOUR_RGB(p, clrRight);
p = rowStart;
p.OffsetY(data, h / 2);
p.OffsetX(data, w / 4); // masked area - left side
ASSERT_EQUAL_COLOUR_RGB(p, clrBg);
p.OffsetX(data, w / 2); // masked area - right side
ASSERT_EQUAL_COLOUR_RGB(p, clrBg);
}
// Drawing the bitmap not using mask
{
wxBitmap bmpOut(w, h, 24);
{
wxMemoryDC dc(bmpOut);
dc.SetBackground(wxBrush(clrBg));
dc.Clear();
dc.DrawBitmap(bmp, wxPoint(0, 0), false);
}
// Check pixels
wxNativePixelData data(bmpOut);
REQUIRE(data);
wxNativePixelData::Iterator p(data);
p.OffsetY(data, h / 4);
wxNativePixelData::Iterator rowStart = p;
p.OffsetX(data, w / 4); // left upper side
ASSERT_EQUAL_COLOUR_RGB(p, clrLeft);
p.OffsetX(data, w / 2); // right upper side
ASSERT_EQUAL_COLOUR_RGB(p, clrRight);
p = rowStart;
p.OffsetY(data, h / 2);
p.OffsetX(data, w / 4); // left lower side - same colour as upper
ASSERT_EQUAL_COLOUR_RGB(p, clrLeft);
p.OffsetX(data, w / 2); // right lower side - same colour as upper
ASSERT_EQUAL_COLOUR_RGB(p, clrRight);
}
}
TEST_CASE("BitmapTestCase::DrawAlpha", "[bitmap][draw][alpha]")
{
const int w = 16;
const int h = 16;
const wxColour clrFg(*wxCYAN);
const wxColour clrBg(*wxGREEN);
const unsigned char alpha = 92;
#if defined(__WXMSW__) || defined(__WXOSX__)
// premultiplied values
const wxColour clrFgAlpha(((clrFg.Red() * alpha) + 127) / 255, ((clrFg.Green() * alpha) + 127) / 255, ((clrFg.Blue() * alpha) + 127) / 255);
#else
const wxColour clrFgAlpha(clrFg);
#endif // __WXMSW__ || __WXOSX__
// Bitmap to be drawn
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() = clrFg.Red();
p.Green() = clrFg.Green();
p.Blue() = clrFg.Blue();
p.Alpha() = 255;
}
else
{ // with transparency
p.Red() = clrFgAlpha.Red();
p.Green() = clrFgAlpha.Green();
p.Blue() = clrFgAlpha.Blue();
p.Alpha() = alpha;
}
}
p = rowStart;
p.OffsetY(data, 1);
}
}
REQUIRE(bmp.HasAlpha());
REQUIRE(bmp.GetMask() == NULL);
// Drawing the bitmap on 24 bpp RGB target
wxBitmap bmpOut24(w, h, 24);
REQUIRE_FALSE(bmpOut24.HasAlpha());
{
wxMemoryDC dc(bmpOut24);
dc.SetBackground(wxBrush(clrBg));
dc.Clear();
dc.DrawBitmap(bmp, wxPoint(0, 0), true);
}
REQUIRE_FALSE(bmpOut24.HasAlpha());
// Check pixels
wxNativePixelData data24(bmpOut24);
REQUIRE(data24);
wxNativePixelData::Iterator p1(data24);
p1.OffsetY(data24, h / 2);
p1.OffsetX(data24, w / 4); // left side is opaque
ASSERT_EQUAL_COLOUR_RGB(p1, clrFg);
p1.OffsetX(data24, w / 2); // right side is with alpha
#if defined(__WXMSW__) || defined(__WXOSX__)
// premultiplied values
ASSERT_EQUAL_RGB(p1, clrFgAlpha.Red() + (clrBg.Red() * (255 - alpha) + 127) / 255,
clrFgAlpha.Green() + (clrBg.Green() * (255 - alpha) + 127) / 255,
clrFgAlpha.Blue() + (clrBg.Blue() * (255 - alpha) + 127) / 255);
#else
ASSERT_EQUAL_RGB(p1, (clrFg.Red() * alpha + clrBg.Red() * (255 - alpha) + 127) / 255,
(clrFg.Green() * alpha + clrBg.Green() * (255 - alpha) + 127) / 255,
(clrFg.Blue() * alpha + clrBg.Blue() * (255 - alpha) + 127) / 255);
#endif // __WXMSW__ || __WXOSX__
#if defined(__WXMSW__) || defined(__WXOSX__)
// Drawing the bitmap on 32 bpp xRGB target
wxBitmap bmpOut32(w, h, 32);
REQUIRE_FALSE(bmpOut32.HasAlpha());
{
wxMemoryDC dc(bmpOut32);
dc.SetBackground(wxBrush(clrBg));
dc.Clear();
dc.DrawBitmap(bmp, wxPoint(0, 0), true);
}
REQUIRE(bmpOut32.GetDepth() == 32);
REQUIRE_FALSE(bmpOut32.HasAlpha());
// Check pixels
wxNative32PixelData data32(bmpOut32);
REQUIRE(data32);
wxNative32PixelData::Iterator p2(data32);
p2.OffsetY(data32, h / 2);
p2.OffsetX(data32, w / 4); // left side is opaque
ASSERT_EQUAL_COLOUR_RGB(p2, clrFg);
p2.OffsetX(data32, w / 2); // right side is with alpha
// premultiplied values
ASSERT_EQUAL_RGB(p2, clrFgAlpha.Red() + (clrBg.Red() * (255 - alpha) + 127) / 255,
clrFgAlpha.Green() + (clrBg.Green() * (255 - alpha) + 127) / 255,
clrFgAlpha.Blue() + (clrBg.Blue() * (255 - alpha) + 127) / 255);
#endif // __WXMSW__ || __WXOSX__
}
TEST_CASE("BitmapTestCase::DrawAlphaWithMask", "[bitmap][draw][alpha][withmask]")
{
const int w = 16;
const int h = 16;
// Mask
wxBitmap bmask = GetMask(w, h);
const wxColour clrFg(*wxCYAN);
const wxColour clrBg(*wxGREEN);
const unsigned char alpha = 92;
#if defined(__WXMSW__) || defined(__WXOSX__)
// premultiplied values
const wxColour clrFgAlpha(((clrFg.Red() * alpha) + 127) / 255, ((clrFg.Green() * alpha) + 127) / 255, ((clrFg.Blue() * alpha) + 127) / 255);
#else
const wxColour clrFgAlpha(clrFg);
#endif // __WXMSW__ || __WXOSX__
// Bitmap with mask to be drawn
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() = clrFg.Red();
p.Green() = clrFg.Green();
p.Blue() = clrFg.Blue();
p.Alpha() = 255;
}
else
{ // with transparency
p.Red() = clrFgAlpha.Red();
p.Green() = clrFgAlpha.Green();
p.Blue() = clrFgAlpha.Blue();
p.Alpha() = alpha;
}
}
p = rowStart;
p.OffsetY(data, 1);
}
}
REQUIRE(bmp.HasAlpha());
REQUIRE(bmp.GetMask() == NULL);
bmp.SetMask(new wxMask(bmask));
REQUIRE(bmp.HasAlpha());
REQUIRE(bmp.GetMask() != NULL);
// Drawing the bitmap on 24 bpp RGB target using mask
{
wxBitmap bmpOut24(w, h, 24);
REQUIRE_FALSE(bmpOut24.HasAlpha());
{
wxMemoryDC dc(bmpOut24);
dc.SetBackground(wxBrush(clrBg));
dc.Clear();
dc.DrawBitmap(bmp, wxPoint(0, 0), true);
}
REQUIRE_FALSE(bmpOut24.HasAlpha());
// Check pixels
wxNativePixelData data24(bmpOut24);
REQUIRE(data24);
wxNativePixelData::Iterator p1(data24);
p1.OffsetY(data24, h / 4);
wxNativePixelData::Iterator rowStart1 = p1;
p1.OffsetX(data24, w / 4); // drawn area - left side opaque
ASSERT_EQUAL_COLOUR_RGB(p1, clrFg);
p1.OffsetX(data24, w / 2); // drawn area - right side with alpha
#if defined(__WXMSW__) || defined(__WXOSX__)
// premultiplied values
ASSERT_EQUAL_RGB(p1, clrFgAlpha.Red() + (clrBg.Red() * (255 - alpha) + 127) / 255,
clrFgAlpha.Green() + (clrBg.Green() * (255 - alpha) + 127) / 255,
clrFgAlpha.Blue() + (clrBg.Blue() * (255 - alpha) + 127) / 255);
#else
ASSERT_EQUAL_RGB(p1, (clrFg.Red() * alpha + clrBg.Red() * (255 - alpha) + 127) / 255,
(clrFg.Green() * alpha + clrBg.Green() * (255 - alpha) + 127) / 255,
(clrFg.Blue() * alpha + clrBg.Blue() * (255 - alpha) + 127) / 255);
#endif // __WXMSW__ || __WXOSX__
p1 = rowStart1;
p1.OffsetY(data24, h / 2);
p1.OffsetX(data24, w / 4); // masked area - left side
ASSERT_EQUAL_COLOUR_RGB(p1, clrBg);
p1.OffsetX(data24, w / 2); // masked area - right side
ASSERT_EQUAL_COLOUR_RGB(p1, clrBg);
}
// Drawing the bitmap on 24 bpp RGB target not using mask
{
wxBitmap bmpOut24(w, h, 24);
REQUIRE_FALSE(bmpOut24.HasAlpha());
{
wxMemoryDC dc(bmpOut24);
dc.SetBackground(wxBrush(clrBg));
dc.Clear();
dc.DrawBitmap(bmp, wxPoint(0, 0), false);
}
REQUIRE_FALSE(bmpOut24.HasAlpha());
// Check pixels
wxNativePixelData data24(bmpOut24);
REQUIRE(data24);
wxNativePixelData::Iterator p1(data24);
p1.OffsetY(data24, h / 4);
wxNativePixelData::Iterator rowStart1 = p1;
p1.OffsetX(data24, w / 4); // left upper side opaque
ASSERT_EQUAL_COLOUR_RGB(p1, clrFg);
p1.OffsetX(data24, w / 2); // right upper side with alpha
#if defined(__WXMSW__) || defined(__WXOSX__)
// premultiplied values
ASSERT_EQUAL_RGB(p1, clrFgAlpha.Red() + (clrBg.Red() * (255 - alpha) + 127) / 255,
clrFgAlpha.Green() + (clrBg.Green() * (255 - alpha) + 127) / 255,
clrFgAlpha.Blue() + (clrBg.Blue() * (255 - alpha) + 127) / 255);
#else
ASSERT_EQUAL_RGB(p1, (clrFg.Red() * alpha + clrBg.Red() * (255 - alpha) + 127) / 255,
(clrFg.Green() * alpha + clrBg.Green() * (255 - alpha) + 127) / 255,
(clrFg.Blue() * alpha + clrBg.Blue() * (255 - alpha) + 127) / 255);
#endif // __WXMSW__ || __WXOSX__
p1 = rowStart1;
p1.OffsetY(data24, h / 2);
p1.OffsetX(data24, w / 4); // left lower side - same colour as upper
ASSERT_EQUAL_COLOUR_RGB(p1, clrFg);
p1.OffsetX(data24, w / 2); // right lower side - same colour as upper
#if defined(__WXMSW__) || defined(__WXOSX__)
// premultiplied values
ASSERT_EQUAL_RGB(p1, clrFgAlpha.Red() + (clrBg.Red() * (255 - alpha) + 127) / 255,
clrFgAlpha.Green() + (clrBg.Green() * (255 - alpha) + 127) / 255,
clrFgAlpha.Blue() + (clrBg.Blue() * (255 - alpha) + 127) / 255);
#else
ASSERT_EQUAL_RGB(p1, (clrFg.Red() * alpha + clrBg.Red() * (255 - alpha) + 127) / 255,
(clrFg.Green() * alpha + clrBg.Green() * (255 - alpha) + 127) / 255,
(clrFg.Blue() * alpha + clrBg.Blue() * (255 - alpha) + 127) / 255);
#endif // __WXMSW__ || __WXOSX__
}
#if defined(__WXMSW__) || defined(__WXOSX__)
// Drawing the bitmap on 32 bpp xRGB target using mask
{
wxBitmap bmpOut32(w, h, 32);
REQUIRE_FALSE(bmpOut32.HasAlpha());
{
wxMemoryDC dc(bmpOut32);
dc.SetBackground(wxBrush(clrBg));
dc.Clear();
dc.DrawBitmap(bmp, wxPoint(0, 0), true);
}
REQUIRE(bmpOut32.GetDepth() == 32);
REQUIRE_FALSE(bmpOut32.HasAlpha());
// Check pixels
wxNative32PixelData data32(bmpOut32);
REQUIRE(data32);
wxNative32PixelData::Iterator p2(data32);
p2.OffsetY(data32, h / 4);
wxNative32PixelData::Iterator rowStart2 = p2;
p2.OffsetX(data32, w / 4); // drawn area - left side opaque
ASSERT_EQUAL_COLOUR_RGB(p2, clrFg);
p2.OffsetX(data32, w / 2); // drawn area - right side with alpha
// premultiplied values
ASSERT_EQUAL_RGB(p2, clrFgAlpha.Red() + (clrBg.Red() * (255 - alpha) + 127) / 255,
clrFgAlpha.Green() + (clrBg.Green() * (255 - alpha) + 127) / 255,
clrFgAlpha.Blue() + (clrBg.Blue() * (255 - alpha) + 127) / 255);
p2 = rowStart2;
p2.OffsetY(data32, h / 2);
p2.OffsetX(data32, w / 4); // masked area - left side
ASSERT_EQUAL_COLOUR_RGB(p2, clrBg);
p2.OffsetX(data32, w / 2); // masked area - right side
ASSERT_EQUAL_COLOUR_RGB(p2, clrBg);
}
// Drawing the bitmap on 32 bpp xRGB target not using mask
{
wxBitmap bmpOut32(w, h, 32);
REQUIRE_FALSE(bmpOut32.HasAlpha());
{
wxMemoryDC dc(bmpOut32);
dc.SetBackground(wxBrush(clrBg));
dc.Clear();
dc.DrawBitmap(bmp, wxPoint(0, 0), false);
}
REQUIRE(bmpOut32.GetDepth() == 32);
REQUIRE_FALSE(bmpOut32.HasAlpha());
// Check pixels
wxNative32PixelData data32(bmpOut32);
REQUIRE(data32);
wxNative32PixelData::Iterator p2(data32);
p2.OffsetY(data32, h / 4);
wxNative32PixelData::Iterator rowStart2 = p2;
p2.OffsetX(data32, w / 4); // left upper side opaque
ASSERT_EQUAL_COLOUR_RGB(p2, clrFg);
p2.OffsetX(data32, w / 2); // right upper side with alpha
// premultiplied values
ASSERT_EQUAL_RGB(p2, clrFgAlpha.Red() + (clrBg.Red() * (255 - alpha) + 127) / 255,
clrFgAlpha.Green() + (clrBg.Green() * (255 - alpha) + 127) / 255,
clrFgAlpha.Blue() + (clrBg.Blue() * (255 - alpha) + 127) / 255);
p2 = rowStart2;
p2.OffsetY(data32, h / 2);
p2.OffsetX(data32, w / 4); // left lower side - same colour as upper
ASSERT_EQUAL_COLOUR_RGB(p2, clrFg);
p2.OffsetX(data32, w / 2); // right lower side - same colour as upper
// premultiplied values
ASSERT_EQUAL_RGB(p2, clrFgAlpha.Red() + (clrBg.Red() * (255 - alpha) + 127) / 255,
clrFgAlpha.Green() + (clrBg.Green() * (255 - alpha) + 127) / 255,
clrFgAlpha.Blue() + (clrBg.Blue() * (255 - alpha) + 127) / 255);
}
#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_COLOUR_RGB(p, clrTopLeft);
p.OffsetX(data, w2 / 2); // top-right point
ASSERT_EQUAL_COLOUR_RGB(p, clrTopRight);
p = rowStart;
p.OffsetY(data, h2 / 2);
p.OffsetX(data, w2 / 4); // bottom-left point
ASSERT_EQUAL_COLOUR_RGB(p, clrBottomLeft);
p.OffsetX(data, w2 / 2); // bottom-right point
ASSERT_EQUAL_COLOUR_RGB(p, clrBottomRight);
}
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_COLOUR_RGB(p, clrTopLeft);
p.OffsetX(data, w2 / 2); // top-right point
ASSERT_EQUAL_COLOUR_RGB(p, clrTopRight);
p = rowStart;
p.OffsetY(data, h2 / 2);
p.OffsetX(data, w2 / 4); // bottom-left point
ASSERT_EQUAL_COLOUR_RGB(p, clrBottomLeft);
p.OffsetX(data, w2 / 2); // bottom-right point
ASSERT_EQUAL_COLOUR_RGB(p, clrBottomRight);
}
// Check sub bitmap mask
wxColour maskClrTopLeft;
wxColour maskClrTopRight;
wxColour maskClrBottomLeft;
wxColour maskClrBottomRight;
#if !defined(__WXOSX__)
REQUIRE(bmpMask.GetDepth() == 1);
#endif
// 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);
// wxMonoPixelData only exists in wxMSW
#if defined(__WXMSW__)
bool maskValueTopLeft;
bool maskValueTopRight;
bool maskValueBottomLeft;
bool maskValueBottomRight;
// Fetch sample original mask pixels
{
REQUIRE(bmpMask.GetDepth() == 1);
wxMonoPixelData data(bmpMask);
REQUIRE(data);
wxMonoPixelData::Iterator p(data);
p.OffsetY(data, h / 4);
wxMonoPixelData::Iterator rowStart = p;
p.OffsetX(data, w / 4); // top-left point
maskValueTopLeft = p.Pixel();
p.OffsetX(data, w / 2); // top-right point
maskValueTopRight = p.Pixel();
p = rowStart;
p.OffsetY(data, h / 2);
p.OffsetX(data, w / 4); // bottom-left point
maskValueBottomLeft = p.Pixel();
p.OffsetX(data, w / 2); // bottom-right point
maskValueBottomRight = p.Pixel();
}
REQUIRE(bmpMask.GetDepth() == 1);
CHECK(maskValueTopLeft == true);
CHECK(maskValueTopRight == true);
CHECK(maskValueBottomLeft == false);
CHECK(maskValueBottomRight == false);
#endif // __WXMSW__
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_COLOUR_RGB(p, maskClrTopLeft);
p.OffsetX(data, w2 / 2); // top-right point
ASSERT_EQUAL_COLOUR_RGB(p, maskClrTopRight);
p = rowStart;
p.OffsetY(data, h2 / 2);
p.OffsetX(data, w2 / 4); // bottom-left point
ASSERT_EQUAL_COLOUR_RGB(p, maskClrBottomLeft);
p.OffsetX(data, w2 / 2); // bottom-right point
ASSERT_EQUAL_COLOUR_RGB(p, maskClrBottomRight);
}
// wxMonoPixelData only exists in wxMSW
#if defined(__WXMSW__)
{
REQUIRE(subBmpMask.GetDepth() == 1);
wxMonoPixelData data(subBmpMask);
REQUIRE(data);
wxMonoPixelData::Iterator p(data);
p.OffsetY(data, h2 / 4);
wxMonoPixelData::Iterator rowStart = p;
p.OffsetX(data, w2 / 4); // top-left point
CHECK(p.Pixel() == maskValueTopLeft);
p.OffsetX(data, w2 / 2); // top-right point
CHECK(p.Pixel() == maskValueTopRight);
p = rowStart;
p.OffsetY(data, h2 / 2);
p.OffsetX(data, w2 / 4); // bottom-left point
CHECK(p.Pixel() == maskValueBottomLeft);
p.OffsetX(data, w2 / 2); // bottom-right point
CHECK(p.Pixel() == maskValueBottomRight);
}
REQUIRE(subBmpMask.GetDepth() == 1);
#endif // __WXMSW__
}
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_COLOUR_RGBA(p, clrLeft);
p.OffsetX(data, w2 / 2); // top-right point
ASSERT_EQUAL_COLOUR_RGBA(p, clrRight);
p = rowStart;
p.OffsetY(data, h2 / 2);
p.OffsetX(data, w2 / 4); // bottom-left point
ASSERT_EQUAL_COLOUR_RGBA(p, clrLeft);
p.OffsetX(data, w2 / 2); // bottom-right point
ASSERT_EQUAL_COLOUR_RGBA(p, clrRight);
}
// Check sub bitmap mask
wxColour maskClrTopLeft;
wxColour maskClrTopRight;
wxColour maskClrBottomLeft;
wxColour maskClrBottomRight;
#if !defined(__WXOSX__)
REQUIRE(bmpMask.GetDepth() == 1);
#endif
// 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);
// wxMonoPixelData only exists in wxMSW
#if defined(__WXMSW__)
bool maskValueTopLeft;
bool maskValueTopRight;
bool maskValueBottomLeft;
bool maskValueBottomRight;
// Fetch sample original mask pixels
{
REQUIRE(bmpMask.GetDepth() == 1);
wxMonoPixelData data(bmpMask);
REQUIRE(data);
wxMonoPixelData::Iterator p(data);
p.OffsetY(data, h / 4);
wxMonoPixelData::Iterator rowStart = p;
p.OffsetX(data, w / 4); // top-left point
maskValueTopLeft = p.Pixel();
p.OffsetX(data, w / 2); // top-right point
maskValueTopRight = p.Pixel();
p = rowStart;
p.OffsetY(data, h / 2);
p.OffsetX(data, w / 4); // bottom-left point
maskValueBottomLeft = p.Pixel();
p.OffsetX(data, w / 2); // bottom-right point
maskValueBottomRight = p.Pixel();
}
REQUIRE(bmpMask.GetDepth() == 1);
CHECK(maskValueTopLeft == true);
CHECK(maskValueTopRight == true);
CHECK(maskValueBottomLeft == false);
CHECK(maskValueBottomRight == false);
#endif // __WXMSW__
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());
}
// wxMonoPixelData only exists in wxMSW
#if defined(__WXMSW__)
{
REQUIRE(subBmpMask.GetDepth() == 1);
wxMonoPixelData data(subBmpMask);
REQUIRE(data);
wxMonoPixelData::Iterator p(data);
p.OffsetY(data, h2 / 4);
wxMonoPixelData::Iterator rowStart = p;
p.OffsetX(data, w2 / 4); // top-left point
CHECK(p.Pixel() == maskValueTopLeft);
p.OffsetX(data, w2 / 2); // top-right point
CHECK(p.Pixel() == maskValueTopRight);
p = rowStart;
p.OffsetY(data, h2 / 2);
p.OffsetX(data, w2 / 4); // bottom-left point
CHECK(p.Pixel() == maskValueBottomLeft);
p.OffsetX(data, w2 / 2); // bottom-right point
CHECK(p.Pixel() == maskValueBottomRight);
}
REQUIRE(subBmpMask.GetDepth() == 1);
#endif // __WXMSW__
}
namespace Catch
{
template <>
struct StringMaker<wxBitmap>
{
static std::string convert(const wxBitmap& bmp)
{
return wxString::Format("bitmap of size %d*%d",
bmp.GetWidth(),
bmp.GetHeight()).ToStdString();
}
};
}
class BitmapColourMatcher : public Catch::MatcherBase<wxBitmap>
{
public:
explicit BitmapColourMatcher(const wxColour& col)
: m_col(col)
{
}
bool match(const wxBitmap& bmp) const wxOVERRIDE
{
const wxImage img(bmp.ConvertToImage());
const unsigned char* data = img.GetData();
for ( int y = 0; y < img.GetHeight(); ++y )
{
for ( int x = 0; x < img.GetWidth(); ++x, data += 3 )
{
if ( wxColour(data[0], data[1], data[2]) != m_col )
return false;
}
}
return true;
}
std::string describe() const wxOVERRIDE
{
return wxString::Format("doesn't have all %s pixels",
m_col.GetAsString()).ToStdString();
}
private:
const wxColour m_col;
};
inline BitmapColourMatcher AllPixelsAre(const wxColour& col)
{
return BitmapColourMatcher(col);
}
TEST_CASE("DC::Clear", "[bitmap][dc]")
{
// Just some arbitrary pixel data.
static unsigned char data[] =
{
0xff, 0, 0,
0, 0xff, 0,
0, 0, 0xff,
0x7f, 0, 0x7f
};
const wxImage img(2, 2, data, true /* don't take ownership of data */);
wxBitmap bmp(img);
SECTION("Clearing uses white by default")
{
{
wxMemoryDC dc(bmp);
dc.Clear();
}
CHECK_THAT(bmp, AllPixelsAre(*wxWHITE));
}
SECTION("Clearing with specified brush works as expected")
{
{
wxMemoryDC dc(bmp);
dc.SetBackground(*wxRED_BRUSH);
dc.Clear();
}
CHECK_THAT(bmp, AllPixelsAre(*wxRED));
}
SECTION("Clearing with transparent brush does nothing")
{
{
wxMemoryDC dc(bmp);
dc.SetBackground(*wxTRANSPARENT_BRUSH);
dc.Clear();
}
CHECK_THAT(bmp.ConvertToImage(), RGBSameAs(img));
}
SECTION("Clearing with invalid brush uses white too")
{
{
wxMemoryDC dc(bmp);
dc.SetBackground(*wxBLACK_BRUSH);
dc.SetBackground(wxBrush());
dc.Clear();
}
CHECK_THAT(bmp, AllPixelsAre(*wxWHITE));
}
}
TEST_CASE("Bitmap::DC", "[bitmap][dc]")
{
#if wxUSE_SVG
TempFile dummySVG("dummy.svg");
wxSVGFileDC dc(dummySVG.GetName());
wxBitmap bmp(10, 10, dc);
CHECK( bmp.IsOk() );
wxImage image(10, 10);
wxBitmap bmpFromImage(image, dc);
CHECK( bmpFromImage.IsOk() );
#endif // wxUSE_SVG
}
#if defined(wxHAS_DPI_INDEPENDENT_PIXELS) || defined(__WXMSW__)
TEST_CASE("Bitmap::ScaleFactor", "[bitmap][dc][scale]")
{
// Create a bitmap with scale factor != 1.
wxBitmap bmp;
bmp.CreateWithDIPSize(8, 8, 2);
REQUIRE( bmp.GetScaleFactor() == 2 );
CHECK( bmp.GetSize() == wxSize(16, 16) );
// wxMemoryDC should use the same scale factor as the bitmap.
wxMemoryDC dc(bmp);
CHECK( dc.GetContentScaleFactor() == 2 );
// A bitmap "compatible" with this DC should also use the same scale factor.
wxBitmap bmp2(4, 4, dc);
CHECK( bmp2.GetScaleFactor() == 2 );
CHECK( bmp2.GetSize() == wxSize(8, 8) );
// A compatible bitmap created from wxImage and this DC should also inherit
// the same scale factor, but its size should be still the same as that of
// the image.
wxImage img(16, 16);
wxBitmap bmp3(img, dc);
CHECK( bmp3.GetScaleFactor() == 2 );
CHECK( bmp3.GetSize() == wxSize(16, 16) );
}
#endif // ports with scaled bitmaps support
#if wxUSE_GRAPHICS_CONTEXT
inline void DrawScaledBmp(wxBitmap& bmp, float scale, wxGraphicsRenderer* renderer)
{
if ( !renderer )
return;
wxBitmap canvas(bmp.GetWidth() * scale, bmp.GetHeight() * scale, 24);
{
wxMemoryDC mdc(canvas);
mdc.SetBackground(*wxBLACK_BRUSH);
mdc.Clear();
wxGraphicsContext* gc = renderer->CreateContext(mdc);
gc->DrawBitmap(bmp, 0, 0, canvas.GetSize().GetWidth(), canvas.GetSize().GetHeight());
delete gc;
}
wxNativePixelData bmpData(bmp);
REQUIRE(bmpData);
wxNativePixelData::Iterator bmpP(bmpData);
wxNativePixelData canvasData(canvas);
REQUIRE(canvasData);
wxNativePixelData::Iterator canvasP(canvasData);
bmpP.MoveTo(bmpData, 0, 0);
canvasP.MoveTo(canvasData, 0, 0);
ASSERT_EQUAL_COLOUR_RGB(bmpP, canvasP);
bmpP.MoveTo(bmpData, bmp.GetWidth() / 2, bmp.GetHeight() / 2);
canvasP.MoveTo(canvasData, canvas.GetWidth() / 2, canvas.GetHeight() / 2);
ASSERT_EQUAL_COLOUR_RGB(bmpP, canvasP);
bmpP.MoveTo(bmpData, bmp.GetWidth() - 1, bmp.GetHeight() - 1);
canvasP.MoveTo(canvasData, canvas.GetWidth() - 1, canvas.GetHeight() - 1);
ASSERT_EQUAL_COLOUR_RGB(bmpP, canvasP);
}
TEST_CASE("GC::DrawBitmap", "[bitmap][drawbitmap]")
{
// Draw a red rectangle to a bitmap, draw the bitmap using a GC to a larger
// canvas and test if the bitmap scaled correctly by checking pixels
// inside and outside the rectangle.
wxBitmap bmp(100, 100, 24);
{
wxMemoryDC mdc(bmp);
mdc.SetBackground(*wxBLACK_BRUSH);
mdc.Clear();
mdc.SetBrush(*wxRED_BRUSH);
mdc.DrawRectangle(20, 20, 60, 60);
}
SECTION("Draw bitmap using default GC")
{
DrawScaledBmp(bmp, 1, wxGraphicsRenderer::GetDefaultRenderer());
}
SECTION("Draw bitmap 0.5x scaled using default GC")
{
DrawScaledBmp(bmp, 0.5, wxGraphicsRenderer::GetDefaultRenderer());
}
SECTION("Draw bitmap 5x scaled using default GC")
{
DrawScaledBmp(bmp, 5, wxGraphicsRenderer::GetDefaultRenderer());
}
#if defined(__WXMSW__) && wxUSE_GRAPHICS_DIRECT2D
SECTION("Draw bitmap using Direct2D GC")
{
DrawScaledBmp(bmp, 1, wxGraphicsRenderer::GetDirect2DRenderer());
}
SECTION("Draw bitmap 0.5x scaled using Direct2D GC")
{
DrawScaledBmp(bmp, 0.5, wxGraphicsRenderer::GetDirect2DRenderer());
}
SECTION("Draw bitmap 5x scaled using Direct2D GC")
{
DrawScaledBmp(bmp, 5, wxGraphicsRenderer::GetDirect2DRenderer());
}
#endif //defined(__WXMSW__) && wxUSE_GRAPHICS_DIRECT2D
}
#endif //wxUSE_GRAPHICS_CONTEXT
#endif //wxHAS_RAW_BITMAP