I want to programmatically create transparent bitmaps based on transparent bitmaps (from PNG files) and DC methods (e.g. DrawRectangle), and later draw them transparently on the window's DC.
To achieve that, I use wxMemoryDC, but it seems that the resulting bitmap is completely screwed up: it is as if the alpha channel is lost, and the whole bitmap is completely transparent, event on the opaque elements.
On my example, I draw two filled red rectangles:
- one from a transparent PNG file (transparent.png)
- one with wxDC.DrawRectangle
This operation is first done directly on the window filled with a ugly coloured gradient, then into a wxBitmap which is drawn and blitted. The bitmap is also saved as a png file "result.png".
In MacOS, the resulting file is correct (2 red rectangles on a transparent background), but not in Windows (a fully transparent bitmap with maybe 2 reds transparent rectangles).
And on the display, this is also not correct.
Is there a bug in wxMSW ?
Code: Select all
#include "wx/wx.h"
class MyApp : public wxApp
{
public:
virtual bool OnInit();
};
class MyFrame : public wxFrame
{
public:
MyFrame(const wxString& title);
private:
void OnPaint(wxPaintEvent &event);
void OnErase(wxEraseEvent &event);
void drawStuff(wxDC *dc);
wxBitmap file_;
DECLARE_EVENT_TABLE()
};
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
if ( !wxApp::OnInit() )
return false;
wxImage::AddHandler(new wxPNGHandler);
MyFrame *frame = new MyFrame(_T("Transparency tests"));
frame->Show(true);
return true;
}
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_PAINT(MyFrame::OnPaint)
EVT_ERASE_BACKGROUND(MyFrame::OnErase)
END_EVENT_TABLE()
MyFrame::MyFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN)
{
file_ = wxBitmap(wxImage(L"transparent.png"));
SetClientSize(wxSize(340, 120));
}
void MyFrame::OnErase(wxEraseEvent &event)
{
wxDC *dc(event.GetDC());
dc->GradientFillLinear(wxRect(GetClientRect()), *wxBLUE, *wxGREEN, wxSOUTH);
}
void MyFrame::drawStuff(wxDC *dc)
{
// draw a red rectangle
dc->SetBrush(*wxRED_BRUSH);
dc->SetPen(*wxTRANSPARENT_PEN);
dc->DrawRectangle(10, 10, 30, 30);
// draw the same rectangle from a file
dc->DrawBitmap(file_, 50, 00, true);
}
void MyFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxPaintDC dc(this);
drawStuff(&dc);
wxBitmap buf(100, 50);
buf.UseAlpha();
wxMemoryDC *memDC = new wxMemoryDC(buf);
memDC->SetBackground(*wxTRANSPARENT_BRUSH);
memDC->Clear();
delete memDC;
memDC = new wxMemoryDC(buf);
drawStuff(memDC);
delete memDC;
buf.SaveFile(_("result.png"), wxBITMAP_TYPE_PNG);
// DrawBitmap
dc.DrawBitmap(buf, 120, 0, true);
dc.DrawBitmap(buf, 120, 70, false);
// blit
memDC = new wxMemoryDC(buf);
dc.Blit(240, 0, 100, 50, memDC, 0, 0);
dc.Blit(240, 70, 100, 50, memDC, 0, 0, wxCOPY, true);
delete memDC;
}