Coder Social home page Coder Social logo

Brush/Pen transparency weirdness about aggdraw HOT 15 OPEN

pytroll avatar pytroll commented on June 7, 2024
Brush/Pen transparency weirdness

from aggdraw.

Comments (15)

djhoese avatar djhoese commented on June 7, 2024

Are you outputting PNG images and that's what you are looking at? Are you showing the image object inside a GUI? What GUI framework? Which version of python? Given that the python 3 support is much less tested than the python 2 version of the library I'd be curious if switching from 3 to 2 changes your results.

Also what OS?

from aggdraw.

a-hurst avatar a-hurst commented on June 7, 2024

Thanks for the quick response! This is running on Python 2.7 on macOS (10.11), and is being rendered to a PyOpenGL context that's created with PySDL2. It's a runtime environment for cognitive psychology experiments, and all shape drawing is done with aggdraw as a back-end (my pictures are just screenshots).

The relevant drawing code is a bit complicated since there's a "shape object" class and a bunch of subclasses with their own drawing methods, but here's the simplified version:

# create drawing context
self.canvas = Image.new("RGBA", self.dimensions, (0, 0, 0, 0))
self.surface = Draw(self.canvas)
self.surface.setantialias(True)
# create fill
if len(color)==3: # fill colour is given in in object init
	color += [255]
self.fill = Brush(tuple(color[:3]), color[3])
# draw shape
self.surface.ellipse([x1, y1, x2, y2], self.stroke, self.fill) # x1, y1, etc. are generated based on given shape dimensions
self.surface.flush() # flush aggdraw drawings to Pillow Image context
self.rendered = numpy.asarray(self.canvas) # render Pillow image to numpy array for PyOpenGL

I'll have to check and see if it still behaves the same if I'm drawing directly to an aggdraw-created context without the Pillow "canvas". For the time being, a workaround that half-fixes it is to create the draw context image with the fill colour of the shape I'm drawing (e.g. Image.new("RGBA", self.dimensions, (192, 192, 192, 0)) makes my example in my original post work as expected).

from aggdraw.

djhoese avatar djhoese commented on June 7, 2024

Is there a reason you have your background fill with an alpha of 0? I get similar results to you in my own tests, but if I set the alpha of the Image to 255 then the results make a lot more sense. I'm not sure you can have predictable results when you are saving a transparent image...right?

from aggdraw.

djhoese avatar djhoese commented on June 7, 2024

Here is my example code:

import aggdraw
from PIL import Image
im = Image.new("RGBA", (100, 100), (255, 255, 255, 255))
draw = aggdraw.Draw(im)
draw.setantialias(True)
fill = aggdraw.Brush((255, 255, 0, 128))
draw.ellipse((25, 25, 75, 75), 2, fill)
draw.flush()

I've swapped the image fill from black to white and 0 to 255 alpha and I'm kind of wondering if the color of a transparent shape over a transparent background is a little undefined.

from aggdraw.

djhoese avatar djhoese commented on June 7, 2024

Or what if you use (255, 255, 255, 0) as the background? Does that make more sense as a result?

from aggdraw.

djhoese avatar djhoese commented on June 7, 2024

Also FYI I get the same results on python 2 and 3 with the version of aggdraw on master (no current changes from last PyPI release).

from aggdraw.

djhoese avatar djhoese commented on June 7, 2024

I get this weird affect without using PIL directly and just using aggdraw's Draw. I wonder if this is a bug in the C++ agg library. aggdraw does use a pretty old version. It is possible something like this has been fixed. It would be difficult to update aggdraw though.

from aggdraw.

a-hurst avatar a-hurst commented on June 7, 2024

The background fill has an alpha of 0 because the generated images are being used as textures by OpenGL, which handles transparency itself (i.e. all shapes and text in my screenshots above are rendered as textures and are then drawn to the display buffer). In order for overlapping textures to be able to blend, they need to be RGBA. Using a background with full opacity results in everything having a square of the background fill colour around it:

screen shot 2018-01-07 at 8 54 37 pm

If I use (255, 255, 255, 0) as the background, the texture gets brighter than it should be if there's any transparency in the shape drawn on it. If set the 'RGB' values of the background are set to the values of the Brush used to draw on it, the opacity works as expected.

Maybe AGG isn't set up to handle transparency properly when drawing to a surface with an alpha channel, so it just uses the same logic as if it's drawing to one with full opacity (i.e blending the brush colour with the background colour)? On a surface with 0 opacity I'd expect it to draw with the unaltered given Brush/Pen colour but with the opacity given (with results like I got with my hacky numpy workaround), but I'm not sure how the logic would work for something being drawn on a surface with, say, half-transparency.

from aggdraw.

a-hurst avatar a-hurst commented on June 7, 2024

There's one fork of aggdraw with the backend updated to AGG 2.4 I've come across, I'll test it out and see if it works. Unfortunately it also has different line join properties (rounded corners by default) which make it not really work as a drop-in replacement for existing projects.

EDIT: Nope, using the 2.4-based aggdraw doesn't fix it either.

from aggdraw.

djhoese avatar djhoese commented on June 7, 2024

@a-hurst This should hopefully be fixed in the current master branch and v1.3.1 release I just made. If you get a chance let me know how it goes.

from aggdraw.

djhoese avatar djhoese commented on June 7, 2024

@a-hurst I just noticed this is still open. Have you tested this lately? Does this work?

from aggdraw.

a-hurst avatar a-hurst commented on June 7, 2024

@a-hurst sorry, I realize it's been a while since you provided a potential fix and I never tested it. In my own code I used the workaround I mentioned above of setting the canvas RGB values to the RGB values of for the shape drawn on it to make everything look right, so since it was working fine that way I'd forgotten about this.

I just tested this again with 1.3.8, and unfortunately it looks like the bug is still present. Here's a screenshot of a paradigm where the Brush for the black shapes is set to 25% transparency ([0, 0, 0, 64]). Here's what it looks like when the Image.new canvas is created with a background colour of (0, 0, 0, 0):

screen shot 2018-11-26 at 12 12 37 am

Here's the exact same thing, except the Image.new canvas is created with a background colour of (255, 255, 255, 0):

screen shot 2018-11-26 at 12 13 45 am

I should really come up with a minimum reproducible example for this, but the above at least illustrates the issue.

from aggdraw.

djhoese avatar djhoese commented on June 7, 2024

Ok thanks. I reread this whole issue and now re-remember what is going on. This is very likely a bug in agg underneath. Even worse is that you said the agg 2.4 fork of this repository didn't fix your issue. That is really our only solution right now. Maybe if we can get this down to some low-level agg calls we can figure this out.

Note: I want to do something similar to this with our satpy library where we draw a ton of lines on an image with a transparent background and then burn the lines on to another image later (or cache the lines on disk). I'm not sure we need transparent lines so we may not run in to the same issue.

from aggdraw.

a-hurst avatar a-hurst commented on June 7, 2024

While trying to dig up info on the Brush size regression w/ the move to 2.4 (i.e. the larger asterisk in #61), I accidentally stumbled upon this, which I think finally explains this bug: https://sourceforge.net/p/agg/discussion/118993/thread/859d8954/

Basically, the expected type of alpha handling here only works if the destination layer format is pixfmt_rgba32_pre, whereas aggdraw's just using regular pixfmt_rgba32 for RGBA shapes. I'll have to look at the docs a bit more to understand how it differs (and whether it would be easy to substitute for pixfmt_rgba32 in aggdraw's case), but at least now we know why this is happening!

from aggdraw.

djhoese avatar djhoese commented on June 7, 2024

Wow! Great find. Any idea what has to happen in the code to make this work?

Side note: What are we going to do about the website being gone?

from aggdraw.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.