wxBitmap: premultiply alpha?
-
- Knows some wx things
- Posts: 27
- Joined: Mon Dec 26, 2016 11:17 pm
wxBitmap: premultiply alpha?
Hello everyone,
I'm having trouble with this, and can't find *any* documentation on it, other than web pages/archives from like 12 years ago. I barely remember the concept of alpha premultiply from working on a QT project a few years ago, but i guess the way wxWidgets handles it is different anyway.
On Linux, there seems to be no premultiply going on. On osx and windows, i get graphic glitches, but different on both, like it works differently on one and the other.
Is there some *reasonably recent* documentation about this? If not, can someone give me a quick briefing about how it's supposed to work? Any help would be greatly appreciated.
I'm having trouble with this, and can't find *any* documentation on it, other than web pages/archives from like 12 years ago. I barely remember the concept of alpha premultiply from working on a QT project a few years ago, but i guess the way wxWidgets handles it is different anyway.
On Linux, there seems to be no premultiply going on. On osx and windows, i get graphic glitches, but different on both, like it works differently on one and the other.
Is there some *reasonably recent* documentation about this? If not, can someone give me a quick briefing about how it's supposed to work? Any help would be greatly appreciated.
-
- Moderator
- Posts: 19164
- Joined: Fri Apr 21, 2006 8:03 pm
- Location: $FCE2
Re: wxBitmap: premultiply alpha?
AFAIK this detail is not officially mentioned anywhere in the documentation. If it were, it should be here:
http://docs.wxwidgets.org/trunk/classwx_pixel_data.html
However, the "image" sample is the only that uses raw bitmap access and it does use premultiplied alpha. So that's the correct way, but only if you use raw bitmap access (using wxPixelData), because that's the only way to manipulate the pixel values directly.
http://docs.wxwidgets.org/trunk/classwx_pixel_data.html
However, the "image" sample is the only that uses raw bitmap access and it does use premultiplied alpha. So that's the correct way, but only if you use raw bitmap access (using wxPixelData), because that's the only way to manipulate the pixel values directly.
Use the source, Luke!
-
- Knows some wx things
- Posts: 27
- Joined: Mon Dec 26, 2016 11:17 pm
Re: wxBitmap: premultiply alpha?
Thanks for the quick reply Doublemax.
I got it to work correctly in linux/gtk and osx by premultiplying the color values by alpha, windows is still giving me several problems. My image is drawn incorrectly (alpha on wxBrush/wxPen seems to be ignored when drawing lines/rectangles), and a straight wxBitmap::GetSubBitmap () of this whole image (after drawing it) gives a blank image.
I got it to work correctly in linux/gtk and osx by premultiplying the color values by alpha, windows is still giving me several problems. My image is drawn incorrectly (alpha on wxBrush/wxPen seems to be ignored when drawing lines/rectangles), and a straight wxBitmap::GetSubBitmap () of this whole image (after drawing it) gives a blank image.
-
- Moderator
- Posts: 19164
- Joined: Fri Apr 21, 2006 8:03 pm
- Location: $FCE2
Re: wxBitmap: premultiply alpha?
Which wxWidgets version? There were several fixes regarding bitmaps with alpha under Windows over the last few months. Unless you're already using the latest version from GIT, try that one.
Drawing bitmaps with alpha should be fine when using wxDCs. But for drawing operations with alpha you need to use wxGraphicsContext under Windows.My image is drawn incorrectly (alpha on wxBrush/wxPen seems to be ignored when drawing lines/rectangles)
Use the source, Luke!
-
- Knows some wx things
- Posts: 27
- Joined: Mon Dec 26, 2016 11:17 pm
Re: wxBitmap: premultiply alpha?
Oh, that's great news! I'm using 3.1.0 now, i will build and test the latest git tonight. Thanks again!doublemax wrote:Which wxWidgets version? There were several fixes regarding bitmaps with alpha under Windows over the last few months. Unless you're already using the latest version from GIT, try that one.
Ah i see. I will read the documentation on that. The same code should also work on osx and linux?Drawing bitmaps with alpha should be fine when using wxDCs. But for drawing operations with alpha you need to use wxGraphicsContext under Windows.
-
- Moderator
- Posts: 19164
- Joined: Fri Apr 21, 2006 8:03 pm
- Location: $FCE2
Re: wxBitmap: premultiply alpha?
YesThe same code should also work on osx and linux?
Use the source, Luke!
-
- Knows some wx things
- Posts: 27
- Joined: Mon Dec 26, 2016 11:17 pm
Re: wxBitmap: premultiply alpha?
Ok, i corrected a few problems i was having with the windows version, but i have a few types of widgets where i render a base image that changes only on resize, or when the data changes etc. and then an overlay image that is updated at each mouse movement, paint event and so on. So i do something like this: (base_image is a member of my class, and overlay_image is local to the redraw function)
This works on linux and osx, but on windows this just gives me a white rectangle :/ I know the base image is drawn (now it's drawn correctly, thanks to the changes with wxGraphicsContext) because if i draw the base image to the paintdc instead of the overlay image, i see what the rendered base image is supposed to look like.
I bump the base image to the overlay at each redraw to avoid flicker caused by drawing both successively to the paintdc. I'd like to do the same on windows if possible.
Any idea what could be causing the blank rectangle?
Code: Select all
myclass::render_base_image () {
base_image = wxBitmap (width, height, 32);
/* draw base image */
}
myclass::redraw (wxDC &paintdc) {
if (some_data_has_changed)
base_image_valid = false;
if (!base_image_valid)
render_base_image ();
wxBitmap overlay_image = wxBitmap (base_image.GetWidth (), base_image.GetHeight (), 32);
wxMemoryDC dc;
dc.SelectObject (overlay_image);
dc.DrawBitmap (base_image, 0, 0); /* also tried with graphiccontext->DrawBitmap (base_image, 0, 0, ...); */
/* draw overlay image */
paintdc.DrawBitmap (overlay_image, 0, 0);
}
I bump the base image to the overlay at each redraw to avoid flicker caused by drawing both successively to the paintdc. I'd like to do the same on windows if possible.
Any idea what could be causing the blank rectangle?
-
- Moderator
- Posts: 19164
- Joined: Fri Apr 21, 2006 8:03 pm
- Location: $FCE2
Re: wxBitmap: premultiply alpha?
If drawing base_image gives a black rectangle, the problem is probably in render_base_image() which you didn't show. That could be tested by loading a bitmap with alpha, e.g. the "toucan.png" from the wx samples. Also, you need to set the "useMask" parameter to true (its meaning is more like useMaskOrAlpha ).
BTW: You don't need to manage a buffer bitmap to avoid flickering yourself, you can just replace wxPaintDC with wx[Auto]BufferedPaintDC.
BTW: You don't need to manage a buffer bitmap to avoid flickering yourself, you can just replace wxPaintDC with wx[Auto]BufferedPaintDC.
Use the source, Luke!
-
- Knows some wx things
- Posts: 27
- Joined: Mon Dec 26, 2016 11:17 pm
Re: wxBitmap: premultiply alpha?
No, because as i mentioned, if i draw the base image instead of the overlay image (at the end of my redraw function) i see what the base image is supposed to look like.doublemax wrote:the problem is probably in render_base_image() which you didn't show.
/* EDIT */
After a bit more debugging, it seems the base image gets copied correctly to the overlay image if i use GetSubBitmap (), but then gets erased to a white rectangle immediately when i call dc.SelectObject (overlay_image); In this case i see a copy of the base image, as expected, but if i add that single call to wxMemoryDC::SelectObject (), it gets erased to a white rectangle on windows. The same code works fine on linux and osx.
Would this have a performance improvement compared to simply bumping the pixel data from the base image to the overlay before rendering the overlay?BTW: You don't need to manage a buffer bitmap to avoid flickering yourself, you can just replace wxPaintDC with wx[Auto]BufferedPaintDC.
-
- Moderator
- Posts: 19164
- Joined: Fri Apr 21, 2006 8:03 pm
- Location: $FCE2
Re: wxBitmap: premultiply alpha?
Try this:
For performance reasons you should use a static bitmap here and only recreate it when the size changes.
However, optimization comes later, first get the output right.
Code: Select all
dc.DrawBitmap (base_image, 0, 0);
dc.SelectObject(wxNullBitmap);
If the only purpose of overlay_image is to reduce flicker, then yes. If you use wxAutoBufferedPaintDC it won't use a buffer bitmap under Linux and OSX because screen output is double buffered by the OS anyway.Would this have a performance improvement compared to simply bumping the pixel data from the base image to the overlay before rendering the overlay?
For performance reasons you should use a static bitmap here and only recreate it when the size changes.
However, optimization comes later, first get the output right.
Use the source, Luke!
-
- Knows some wx things
- Posts: 27
- Joined: Mon Dec 26, 2016 11:17 pm
Re: wxBitmap: premultiply alpha?
I'm having another similar problem with setting my pixel values with a wxAlphaPixelData::Iterator ...for some reason windows refuses to make them transparent, even if i set the alpha value to 0. It will always show up as opaque when i draw that image on another image with a wxMemoryDC. I tried all combinations of premultiplying color values with alpha, selecting the image in a temporary wxMemoryDC and clearing it with a "transparent" brush, etc etc..... again, works fine on osx and linux, but winpieceofsh!#%t is causing trouble as usual.
-
- Moderator
- Posts: 19164
- Joined: Fri Apr 21, 2006 8:03 pm
- Location: $FCE2
Re: wxBitmap: premultiply alpha?
Can you show a minimal, compilable piece of code that shows the problem? (no pseudo code please)
Use the source, Luke!
-
- Knows some wx things
- Posts: 27
- Joined: Mon Dec 26, 2016 11:17 pm
Re: wxBitmap: premultiply alpha?
Should display a blue background with a red square that gradients in opacity from transparent (top) to opaque (bottom).
Fails on windows (fully opaque red square)
Fails on windows (fully opaque red square)
Code: Select all
/*
* compile & run:
* g++ wxtest.cpp `wx-config --cflags --libs` -o wxtest && ./wxtest
*
* Should display a blue background with a red square that gradients in
* opacity from transparent (top) to opaque (bottom)
*/
#include <wx/wx.h>
#include <wx/rawbmp.h>
class c_panel : public wxPanel {
public:
void paint_event (wxPaintEvent &ev) {
wxPaintDC dc (this);
int x, y;
/* blue bacbkground */
dc.SetBackground (wxBrush (wxColour (0, 0, 255, 255)));
dc.Clear ();
wxBitmap bitmap (128, 128, 32);
wxAlphaPixelData pixeldata (bitmap);
wxAlphaPixelData::Iterator p (pixeldata);
p.MoveTo (pixeldata, 0, 0);
/* red square, with alpha gradient */
for (y = 0; y < 128; ++y) {
wxAlphaPixelData::Iterator rowstart = p;
for (x = 0; x < 128; ++x, ++p) {
p.Red () = 255;
p.Green () = 0;
p.Blue () = 0;
p.Alpha () = y * 2;
}
p = rowstart;
p.OffsetY (pixeldata, 1);
}
dc.DrawBitmap (bitmap, 128, 64);
}
/* ctor */
c_panel (wxWindow *parent, int id) : wxPanel (parent, id) {
SetMinClientSize (wxSize (384, 256));
SetMaxClientSize (wxSize (384, 256));
Bind (wxEVT_PAINT, &c_panel::paint_event, this);
}
};
class c_testapp : public wxApp {
public:
wxFrame *frame;
wxSizer *sizer;
c_panel *panel;
bool OnInit () {
sizer = new wxBoxSizer (wxHORIZONTAL);
frame = new wxFrame (NULL, wxID_ANY, "Test");
frame->SetSizer (sizer);
panel = new c_panel (frame, wxID_ANY);
sizer->Add (panel);
frame->Show ();
frame->SetClientSize (wxSize (384, 256));
return true;
}
};
IMPLEMENT_APP (c_testapp);
-
- Moderator
- Posts: 19164
- Joined: Fri Apr 21, 2006 8:03 pm
- Location: $FCE2
Re: wxBitmap: premultiply alpha?
1) You have to premultiply the RGB values with alpha
2) The wxAlphaPixelData object must be destroyed before you draw the bitmap
2) The wxAlphaPixelData object must be destroyed before you draw the bitmap
Code: Select all
wxPaintDC dc (this);
int x, y;
/* blue bacbkground */
dc.SetBackground (wxBrush (wxColour (0, 0, 255)));
dc.Clear ();
wxBitmap bitmap (128, 128, 32);
{
wxAlphaPixelData pixeldata (bitmap);
wxAlphaPixelData::Iterator p (pixeldata);
p.MoveTo (pixeldata, 0, 0);
/* red square, with alpha gradient */
for (y = 0; y < 128; ++y)
{
wxAlphaPixelData::Iterator rowstart = p;
for (x = 0; x < 128; ++x, ++p)
{
unsigned char alpha = y * 2;
p.Red () = 255 * alpha / 255;
p.Green () = 0 * alpha / 255;
p.Blue () = 0 * alpha / 255;
p.Alpha () = alpha;
}
p = rowstart;
p.OffsetY (pixeldata, 1);
}
}
dc.DrawBitmap (bitmap, 128, 64);
Use the source, Luke!