Some questions on Alpha

I’ve been experimenting with wxPython (v3.0) for a bit trying to build a pixel paint tool. I’ve got some of it working so far but whenever I paint a single pixel it also “echos” another one just to the lower right of the intended point (anti-aliasing is disabled). Funny thing is if I use a non-alpha color instead it paints a single pixel just fine. There also doesn’t seem to be a way to get specific alpha pixel data out of bitmaps (which seem to be required for drawing or using things like floodfill), as converting them to an image with ImageFromBitmap() or ConvertToImage() seems to strip the alpha layer in the process. Converting Images with alpha enabled to bitmaps seems to work fine though.

Any suggestions or insights?

example.zip (2.66 KB)

Try converting bitmap data to numpy arrays and operate directly there.

HTH
Niki

···

On 29.12.2016 10:38, magurp244@gmail.com wrote:

I've been experimenting with wxPython (v3.0) for a bit trying to build a
pixel paint tool. I've got some of it working so far but whenever I
paint a single pixel it also "echos" another one just to the lower right
of the intended point (anti-aliasing is disabled). Funny thing is if I
use a non-alpha color instead it paints a single pixel just fine. There
also doesn't seem to be a way to get specific alpha pixel data out of
bitmaps (which seem to be required for drawing or using things like
floodfill), as converting them to an image with ImageFromBitmap() or
ConvertToImage() seems to strip the alpha layer in the process.
Converting Images with alpha enabled to bitmaps seems to work fine though.

Any suggestions or insights?

magurp244@gmail.com wrote:

I've been experimenting with wxPython (v3.0) for a bit trying to build
a pixel paint tool. I've got some of it working so far but whenever I
paint a single pixel it also "echos" another one just to the lower
right of the intended point (anti-aliasing is disabled). Funny thing
is if I use a non-alpha color instead it paints a single pixel just
fine. There also doesn't seem to be a way to get specific alpha pixel
data out of bitmaps (which seem to be required for drawing or using
things like floodfill), as converting them to an image with
ImageFromBitmap() or ConvertToImage() seems to strip the alpha layer
in the process. Converting Images with alpha enabled to bitmaps seems
to work fine though.

Any suggestions or insights?

Because it is a cross-platform library, wxWidgets necessarily involves a
large number of compromises. Even on Windows, it's not always clear
what a single API means. You are using a wx.GCDC, which is implemented
using GDIplus in Windows, as opposed to the normal wx.DC, which goes
directly to GDI. GDIplus was designed for higher-level drawing, and as
such sometimes gives up pixel-precision for the sake of beauty.

In this particular case, the underlying wxGCDC class in C++ does not
actually implement DrawPoint, because the GDIplus API does not have a
function to set a single pixel. Thus, the call falls back to
simulations and translations. You would see different results with
wx.DC, and you would see different results on the other platforms.

If you want pixel-accurate drawing with alpha, then you need to do the
drawing yourself in a pixel array backed by a wx.Image, and just use wx
to refresh your wx.Image on the screen.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

@niki
The thought has occured to me since and I may go that way, though the pixel percision is a bit of a sticking point.

@Tim
Hm, thanks for clearing that up. I’m not opposed to using arrays for managing image data, its something i’ve done before with Pyglet and was already going to implement to a degree. However I was hoping I could make use of some of wxpythons built in draw tool functions like circle, floodfill, etc. as some of them are more efficient than what i’ve previously implemented. If I understand correctly though, wx.DC/GDI would be pixel-accurate sans alpha? If thats the case I may try using a bitmap/image as a proxy alpha layer and draw to one of its RGB color channels in memory, then extract that and apply it to an image array as an alpha channel before redrawing it.

Thank you everyone for your responses.

Hm, thanks for clearing that up. I'm not opposed to using arrays for managing image data, its something i've done before with Pyglet and was already going to implement to a degree. However I was hoping I could make use of some of wxpythons built in draw tool functions like circle, floodfill, etc. as some of them are more efficient than what i've previously implemented.

Only in some circumstances. Over the past year, I have evolved a relatively complicated telemetry front-end C++ application that used to use ATL on Windows, into one based on wxWidgets. It now compiles and runs on Windows, OS X, Linux locally, and Linux over X. It has been an education, to put it mildly. Many concepts that work great on Windows simply don't work in other places, and optimizing the performance for multiple platforms is a process that is STILL going on. Some of the wx operations that you'd think are being done by your graphics card are instead being translated, simulated, and translated back. So, "efficient" is a word that means different things in different contexts.

If you're doing a lot of off-screen drawing, you MIGHT want to investigate a separate library dedicated strictly to pixel operations. It depends on how much you're doing.

If I understand correctly though, wx.DC/GDI would be pixel-accurate sans alpha?

Yes, that has always been the goal of GDI. There are tests that GDI drivers have to pass that compare bitmap results pixel by pixel.

If thats the case I may try using a bitmap/image as a proxy alpha layer and draw to one of its RGB color channels in memory, then extract that and apply it to an image array as an alpha channel before redrawing it.

If Windows is your only target, this might do the job.

···

On Dec 30, 2016, at 2:14 PM, magurp244@gmail.com wrote:

Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

You may want to give libgd a try. It's a venerable old C drawing lib, and
though it's been updated to support ani-aliasing, alpha, etc, the old
simple 8bit drawing is all still there, and robust and fast.

I've written a new Python wrapper for it that (I think) is Pythonic and
clean and can push-pull native numpy arrays:

code here:

binary conda packages on the NOAA-ORR-ERD channel:

https://anaconda.org/NOAA-ORR-ERD/repo

conda install py_gd -c NOAA-ORR-ERD

I haven't used it with wx (yet) but it should be pretty efficient ot
push-pull libgd images to/from wxImages for display on the screen:

This is kinda old, but should get you started:

https://wiki.wxpython.org/WorkingWithImages

-CHB

···

On Sun, Jan 1, 2017 at 11:51 AM, Tim Roberts <timr@probo.com> wrote:

If you're doing a lot of off-screen drawing, you MIGHT want to investigate
a separate library dedicated strictly to pixel operations. It depends on
how much you're doing.

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Only in some circumstances. Over the past year, I have evolved a relatively complicated telemetry front-end C++ application that used to use ATL on Windows, into one based on wxWidgets. It now compiles and runs on Windows, OS X, Linux locally, and Linux over X. It has been an education, to put it mildly. Many concepts that work great on Windows simply don’t work in other places, and optimizing the performance for multiple platforms is a process that is STILL going on. Some of the wx operations that you’d think are being done by your graphics card are instead being translated, simulated, and translated back. So, “efficient” is a word that means different things in different contexts.

If you’re doing a lot of off-screen drawing, you MIGHT want to investigate a separate library dedicated strictly to pixel operations. It depends on how much you’re doing.

Well, to put things in perspective in this particular case, my last project (another paint tool on windows) I made with Pyglet using ndarray transformations for the tools, which all worked well except for the floodfill. On windows it takes 55 seconds for it to fill a 2000x2000 area, whereas wxPython takes 1 second for the same operation. It may provide different results under different circumstances, but I can’t help but see that as an improvement. :wink:

You may want to give libgd a try. It’s a venerable old C drawing lib, and though it’s been updated to support ani-aliasing, alpha, etc, the old simple 8bit drawing is all still there, and robust and fast.

Thanks for mentioning it! I’ll be sure to give it a look, I can always use more API’s to play around with, heh.

If Windows is your only target, this might do the job.

Currently windows is my only target, though there may be a linux distro somewhere in the distant future. As it turns out my little array trick works pretty good, although there were a few caveats. As it turns out when drawing an image with alpha, the alpha pixels stack with previously drawn images eventually turning them into solid colors (visually anyway). So I did a dc.Clear() before each draw call but that creates seizure inducing flicker on every draw. So I went back and simulated the alpha on a solid rgb bitmap so I wouldn’t have to clear the background and that fixed the flicker, although if you paint too rapidly there’s still a noticable delay.

Somewhere between all that I also decided to try a glcontext and came across [PygletWX] to plug in a pyglet subclass of a wx.Panel. The results were actually alot better than I was expecting, and the two work pretty well together. It ended up being the better of the 3, supporting full alpha, no flicker, and a rapid draw response. I’ve attached examples of all 3 approaches in case anyone now or in the future has any interest.

Alpha-Example.zip (18 KB)