0

这使用 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

4

0 回答 0