开罗(w/Python):是否可以用透明线填充多边形?
这是我现在使用的代码:
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()
问题是它用我绘制的相同颜色填充多边形。我尝试在这个多边形上绘制一个新的多边形,并只执行 context.lines()
而不是 fill()
但只有当我使用不同的颜色时才有效,因为否则下面是白色。我尝试使用 (0,0,0,0)
所以它是透明的,但白色在它下面。
我可以绘制一条彩色线(例如 (0.5,0.5,0.5,1)
),使用 write_to_png
将其保存到图像中,使用 PIL 加载它,转换为 numpy .array 并将每个像素替换为背景颜色 (0, 0, 0, 0)
的正确颜色,但这效率不高。
我还尝试将线宽设置为 0,但这也不起作用。
另外,我对开罗以外的其他方法也很满意。我已经尝试过 ImageDraw 的 polygon
但它没有绘制确切的形状(我不知道如何解释,但它在多边形之外绘制了一些不应该的额外像素) ,所以 ImageDraw 对我没有帮助。
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 otherwise 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我现在明白了。所以,没有办法做到这一点 - 所有 2D 绘图 API 的开罗风格都假设“填充”包括边框。它在 Cairo 渲染的大多数后端(例如 Postscript 和 SVG)上都以这种方式工作,因此很难想象它会有什么不同。
“干净”的方法是迭代多边形,以便生成仅界定您想要填充的区域的点 - 即,您必须自己计算线面积。
另一方面,你的黑客似乎很聪明,不可能完全在开罗完成它,因为它处理光栅。但除了保存到磁盘并重新加载之外,您还可以采取其他方法 - 例如,您可以使用开罗表面数据作为 Pygame 中的 SDL 表面来伪造“复制和粘贴”操作。
http://doswa.com/blog/2010/03/ 29/使用-cairo-in-pygame/
http://www.pygame.org/wiki/CairoPygame
(实际上,我试图思考使用 Pyagame 的工作流程,但无法 - 选项
用于操纵 alpha 像素并对其进行复制/粘贴相当有限)。
我给你的最后建议:不要使用 pycairo -
检查使用 GIMP Python API 是否适合您。
GIMP 是一个功能齐全的 2D 绘图程序,具有可以从 Python 使用的完整 API。您可以使用 GIMP“矢量”对象绘制多边形,尽管“填充”
还将包括多边形线,有一个“gimp_selection_shrink”,您可以
例如,在填充之前调用 jsut 。或者,您可以利用图层来获得您想要的确切效果。
在 GIMP 内部,您可以在“帮助”->“程序数据库”菜单中检查整个 API。
一旦您的脚本准备就绪,就可以使用命令行运行 GIMP 来运行您的程序,而不需要图形显示。
以下是使用 pygimp 所需的工作流程:
pdb.gimp_image_add_vectors, pdb.gimp_vectors_lines_new_from_points
pdb.gimp_layer_new (必须调用一些其他函数才能将图层绑定到图像)
pdb.gimp_selection_border
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:
pdb.gimp_image_add_vectors, pdb.gimp_vectors_stroke_new_from_points
pdb.gimp_layer_new (there are some other functions that have to be called to bind the layer to the image)
pdb.gimp_selection_border