这使用 aggdraw 和 PIL Image。
所以我正在尝试使用贝塞尔曲线生成一些形状。但问题是移除绘图的内部部分。如果我使用内部路径和外部路径,它只会填充两者,如果我将它们分开并为内部使用透明画笔,它不会做任何事情。
说如果你想画一个甜甜圈,你如何去除这个洞?
似乎不可能用 aggdraw 擦除像素,所以....也许我错过了一些东西。
问题一:你能用透明画笔在像素变成透明的地方画画吗?
问题二:如何擦除像素、多边形和路径?当然我可以使用面具,但我必须创建面具,所以回到同样的问题。
最后,有一些图像是我的要点,下面的链接。一种是使用代码生成路径数据,然后用gimp进行绘制,也就是目标渲染。另一个是我的代码实际生成的图像。
要点示例:[ https://gist.github.com/ismaelharunid/49df974a59ad98be6934deb8d38154ce
from PIL import Image
import aggdraw
from math import sqrt, cos, sin, pi
lerp = lambda a, b=0.0, t=0.5: a + (b-a) * t
circle4k = 0.55191502449
radius_circle_bpd = lambda radius: \
( 0., radius
, circle4k*radius, radius
, radius, circle4k*radius
, radius, 0.
, radius, -circle4k*radius
, circle4k*radius, -radius
, 0., -radius
, -circle4k*radius, -radius
, -radius, -circle4k*radius
, -radius, 0.
, -radius, circle4k*radius
, -circle4k*radius, radius
, 0., radius )
rectangle_pd = lambda x0,y0, x1,y1: (x0,y0, x1,y0, x1,y1, x0,y1, x0,y0)
pd_translate = lambda pd, offset, nc=2: tuple( pd[ir+ic] + offset[ic] \
for ir in range(0, len(pd), nc) for ic in range(nc) )
pd_scale = lambda pd, delta, nc=2: tuple( pd[ir+ic] * delta[ic] \
for ir in range(0, len(pd), nc) for ic in range(nc) )
pd_transform = lambda pd, m, nc=2: \
tuple(sum(pd[ir+i]*m[ic+i*nc] for i in range(nc)) \
for ir in range(0, len(pd), nc) for ic in range(nc))
new_draw = lambda size: aggdraw.Draw(Image.new("RGBA", size))
def bpd_add_path(*bpds, path=None):
if path is None: path = aggdraw.Path()
for bpd in bpds:
path.moveto(*bpd[:2])
for i in range(2, len(bpd), 6):
path.curveto(*bpd[i:i+6])
return path
def saturn_im(size=(540, 540), angle=pi/10, circle_radius=None
, ring_inner_radius=None, ring_outer_radius=None
, n_rings=3, ring_ratio=0.85, ring_aspect=0.5
, circle_color='#bc75ff', rings_color='#bcff75'
, outline_color='#ccbd14', outline_weight=4.5):
offset = (.5 * size[0], .5 * size[1])
if circle_radius is None:
circle_radius = min(offset) / 3.
if ring_inner_radius is None:
ring_inner_radius = circle_radius / .80
if ring_outer_radius is None:
ring_outer_radius = offset[0]
ca, sa = cos(angle), sin(angle)
matrix = (ca, sa,-sa, ca)
pdmask = \
pd_translate( \
pd_transform( \
rectangle_pd(-offset[0],-offset[1], offset[0],offset[1]) \
, matrix )
, offset )
bpdcircle = \
pd_translate( \
pd_transform( \
radius_circle_bpd(circle_radius) \
, matrix )
, offset )
r0, r1 = ring_ratio**5, ring_ratio**0
rspan, sspan = r1 - r0, ring_outer_radius - ring_inner_radius
rlerp = lambda i: ring_inner_radius+sspan*(ring_ratio**i-r0) / rspan
bpdrings = tuple( \
pd_translate( \
pd_transform( \
pd_scale( \
radius_circle_bpd(rlerp(i_rings)) \
, (1.0, ring_aspect) )
, matrix )
, offset ) for i_rings in range(n_rings * 2))
for i in range(6):
print(i, min(bpdrings[i]),max(bpdrings[i]))
print("Paths created")
penstroke = aggdraw.Pen(outline_color, outline_weight)
brushcircle = aggdraw.Brush(circle_color)
brushrings = aggdraw.Brush(rings_color)
brusheraser = aggdraw.Brush((0,0,0,0))
print("Resources created")
imcircle = new_draw(size)
imcircle.path(bpd_add_path(bpdcircle), penstroke, brushcircle)
imcircle = imcircle.flush()
print("Circle created")
imrings = new_draw(size)
#imrings.path(bpd_add_path(*bpdrings), penstroke, brushrings)
#imrings.path(bpd_add_path(bpdrings[0]), penstroke, brushrings)
#imrings.path(bpd_add_path(bpdrings[1]), penstroke, brusheraser)
imrings.path(bpd_add_path(bpdrings[2]), penstroke, brushrings)
imrings.path(bpd_add_path(bpdrings[3]), penstroke, brusheraser)
#imrings.path(bpd_add_path(bpdrings[4]), penstroke, brushrings)
#imrings.path(bpd_add_path(bpdrings[5]), penstroke, brusheraser)
imrings = imrings.flush()
print("Rings created")
im = Image.new("RGBA", size, '#000000')
im.paste(imrings, mask=imrings)
im.paste(imcircle, mask=imcircle)
print("Doughnut created")
return im
好的,所以我的问题仍然存在,但我找到了一种解决方法,这可能是大多数人的做法。使用蒙版,是的,我可以在 L 模式(灰度)下绘画,然后在东边画出或在每个你想做的蒙版中画出或画出。然后你必须应用面具。有点乏味,但它完成了工作。修改后的代码有效...
from PIL import Image
import aggdraw
from math import sqrt, cos, sin, pi
lerp = lambda a, b=0.0, t=0.5: a + (b-a) * t
circle4k = 0.55191502449
radius_circle_bpd = lambda rx, ry=None: _radius_circle_bpd(rx, rx if ry is None else ry)
_radius_circle_bpd = lambda rx, ry: \
( 0., ry
, circle4k*rx, ry
, rx, circle4k*ry
, rx, 0.
, rx, -circle4k*ry
, circle4k*rx, -ry
, 0., -ry
, -circle4k*rx, -ry
, -rx, -circle4k*ry
, -rx, 0.
, -rx, circle4k*ry
, -circle4k*rx, ry
, 0., ry )
rectangle_pd = lambda x0,y0, x1,y1: (x0,y0, x1,y0, x1,y1, x0,y1, x0,y0)
pd_translate = lambda pd, offset, nc=2: tuple( pd[ir+ic] + offset[ic] \
for ir in range(0, len(pd), nc) for ic in range(nc) )
pd_scale = lambda pd, delta, nc=2: tuple( pd[ir+ic] * delta[ic] \
for ir in range(0, len(pd), nc) for ic in range(nc) )
pd_transform = lambda pd, m, nc=2: \
tuple(sum(pd[ir+i]*m[ic+i*nc] for i in range(nc)) \
for ir in range(0, len(pd), nc) for ic in range(nc))
new_draw = lambda size: aggdraw.Draw(Image.new("RGBA", size))
new_mask = lambda size, color="black": aggdraw.Draw(Image.new("L", size, color))
def bpd_add_path(*bpds, path=None):
if path is None: path = aggdraw.Path()
for bpd in bpds:
path.moveto(*bpd[:2])
for i in range(2, len(bpd), 6):
path.curveto(*bpd[i:i+6])
return path
def pd_add_path(*bpds, path=None):
if path is None: path = aggdraw.Path()
for bpd in bpds:
path.moveto(*bpd[:2])
for i in range(2, len(bpd), 2):
path.lineto(*bpd[i:i+2])
return path
def saturn_im(size=(540, 540), angle=pi/10, circle_radius=None
, ring_inner_radius=None, ring_outer_radius=None
, n_rings=3, ring_ratio=0.85, ring_aspect=0.5
, circle_color='#bc75ff', rings_color='#bcff75'
, outline_color='#ccbd14', outline_weight=4.5):
offset = (.5 * size[0], .5 * size[1])
if circle_radius is None:
circle_radius = min(offset) / 3.
if ring_inner_radius is None:
ring_inner_radius = circle_radius / .80
if ring_outer_radius is None:
ring_outer_radius = offset[0]
ca, sa = cos(angle), sin(angle)
matrix = (ca, sa,-sa, ca)
pdmask = \
pd_translate( \
pd_transform( \
rectangle_pd(-offset[0],-offset[1], offset[0],0) \
, matrix )
, offset )
bpdcircle = \
pd_translate( \
pd_transform( \
radius_circle_bpd(circle_radius) \
, matrix )
, offset )
r0, r1 = ring_ratio**(n_rings*2-1), ring_ratio**0
rspan, sspan = r1 - r0, ring_outer_radius - ring_inner_radius
rlerp = lambda i: ring_inner_radius+sspan*(ring_ratio**i-r0) / rspan
bpdrings = tuple( \
pd_translate( \
pd_transform( \
pd_scale( \
radius_circle_bpd(rlerp(i_rings)) \
, (1.0, ring_aspect) )
, matrix )
, offset ) for i_rings in range(n_rings * 2))
for i in range(6):
print(i, min(bpdrings[i]),max(bpdrings[i]))
print("Paths created")
penstroke = aggdraw.Pen(outline_color, outline_weight)
penwhite = aggdraw.Pen("white", outline_weight)
penblack = aggdraw.Pen("black", outline_weight)
brushcircle = aggdraw.Brush(circle_color)
brushrings = aggdraw.Brush(rings_color)
brushwhite = aggdraw.Brush("white")
brushblack = aggdraw.Brush("black")
print("Resources created")
imcircle = new_draw(size)
imcircle.path(bpd_add_path(bpdcircle), penstroke, brushcircle)
imcircle = imcircle.flush()
print("Circle created")
imcirclemask = new_mask(size, "white")
imcirclemask.path(bpd_add_path(bpdcircle), penblack, brushblack)
imcirclemask.path(pd_add_path(pdmask), brushwhite)
imcirclemask = imcirclemask.flush()
#imcirclemask.show()
print("Circle mask created")
imrings = new_draw(size)
imrings.path(bpd_add_path(*bpdrings), penstroke, brushrings)
imrings = imrings.flush()
#imrings.show()
print("Rings created")
tmpmask = new_mask(size, "black")
for i in range(0, 2*n_rings, 2):
tmpmask.path(bpd_add_path(bpdrings[i+0]), penwhite, brushwhite)
tmpmask.path(bpd_add_path(bpdrings[i+1]), penwhite, brushblack)
tmpmask = tmpmask.flush()
#tmpmask.show()
imringsmask = Image.new("L", size, "black")
imringsmask.paste(tmpmask, mask=imcirclemask)
#imringsmask.show()
print("Rings mask created")
im = Image.new("RGBA", size, '#000000')
im.paste(imcircle, mask=imcircle)
im.paste(imrings, mask=imringsmask)
print("Doughnut created")
return im
还有田……
[ https://user-images.githubusercontent.com/26759688/84541494-16bdf180-ad2a-11ea-805e-29388f992070.png