画图:用透明画图或擦除透明画图。似乎没有办法擦除或绘制透明像素

2024-06-01 09:53:44 发布

您现在位置:Python中文网/ 问答频道 /正文

这是使用aggdraw与PIL图像

所以我尝试用贝塞尔曲线生成一些形状。但问题是删除图形的内部部分。如果我使用一个内部和外部路径,它只会填充这两个路径,如果我将它们分开,并使用一个透明的笔刷填充内部路径,它不会做任何事情

比如说,如果你想画一个油炸圈饼,你怎么去掉这个洞

似乎不可能用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


Tags: pathlambdainnoneforsizerangeoffset