开发者

Cairo (w/ Python): Is it possible to fill a Polygon with a transparent line?

开发者 https://www.devze.com 2023-02-18 08:21 出处:网络
Here\'s the code I\'m using right now: surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *image.size) context = cairo.Context(surface)

Here's the code I'm using right now:

surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *image.size)
context = cairo.Context(surface)
context.set_source_rgba(1, 1, 1, 1)
context.new_path()
for i in xrange(len(points)):
    context.line_to(*points[i])

context.close_path()
context.fill()

The problem is that it fills the polygon with the same color I draw. I tried drawing a new polygon over this one and doing just context.stroke() instead of fill() but that only works if I use a different color, since otherwis开发者_StackOverflow中文版e the white color is under. I tried with (0,0,0,0) so it would be transparent, but then the white is below it.

I can draw a colored line (say (0.5,0.5,0.5,1)), save it to an image with write_to_png, load it with PIL, convert to a numpy.array and replace each pixel with the right color with the background color (0, 0, 0, 0) but that's not efficient.

I also tried setting the line width to 0 and that doesn't work either.

Also, I'm fine with other methods that let me do this that aren't Cairo. I've tried ImageDraw's polygon but it doesn't draw the exact shape (I'm not sure how to explain, but it sort of draws some extra pixels outside of the polygon where it shouldn't), so ImageDraw won't help me.


fill_preserve()
context.set_source_rgba(0, .6, 1, .7) #line color
context.set_line_width(2.35)
context.stroke()


I got it now. SO, there is no way to do it - all 2D drawing API's on Cairo's style assume that "filling" includes the border. It works this way on most backends Cairo renders to, like Postscript and SVG, so it is hard to imagine how it could be different.

The "clean" way to do it is to iterate over your polygon so that you generate points that delimit only the area you wan t filled - i.e., you have to calculate the line area yourself.

Your hack, on the other hand, seems clever, it is not possible to do it entirely in Cairo since it deals with raster. But instead of saving to disk and reloading, there are other ways you could take - for example, you could use the Cairo surface data as an SDL surface in Pygame to fake "copy and paste" operations.

http://doswa.com/blog/2010/03/29/using-cairo-in-pygame/ http://www.pygame.org/wiki/CairoPygame

(Actually,. I tried to think a workflow using Pyagame and could not - the options for manipulating alpha pixels and copy/pasting on it are rather limited).

My final suggestion for you: Do not use pycairo for that - Check if using the GIMP Python API is suitable for you. GIMP is a fully featured 2D drawing program with a complete API that can be used from Python. You can draw yur polygons with GIMP "Vectors" objects, and although the "fill" there will also include the polygon line, there is a "gimp_selection_shrink" you can call jsut before filling, for example. Or, you can make use of layers to get the exact effect you want.

From inside GIMP you can check the whole API in the Help->Procedure databse menu.

Once your script is ready, it is possible to run GIMP with a coomand line to run your program, without the need of a graphics display.

Here is the workflow you need using pygimp:

  • Create GIMP vectors object with your poligon points: pdb.gimp_image_add_vectors, pdb.gimp_vectors_stroke_new_from_points
  • Create a new layer (above the layer with the image you want to preserve along the line) pdb.gimp_layer_new (there are some other functions that have to be called to bind the layer to the image)
  • Convert your polygon to selection - pdb.gimp_vectors_to_selection
  • Fill the new layer, with the desired color pdb.gimp_edit_bucket_fill
  • Convert the selection to a "thick" selection with pdb.gimp_selection_border
  • Cut pixels from the layer - pdb.gimp_Edit_cut
  • Merge the new layer into your previous image - pdb.gimp_image_merge_down
0

精彩评论

暂无评论...
验证码 换一张
取 消