Python图像库(PIL)绘图--带渐变的圆角矩形

Python图像库(PIL)绘图--带渐变的圆角矩形,python,drawing,python-imaging-library,gradient,Python,Drawing,Python Imaging Library,Gradient,我正在尝试使用PIL来绘制一个圆角矩形和颜色的渐变填充。我发现一个很酷的网站()展示了如何绘制一个纯色圆形矩形,我对此很满意,但我希望能够绘制一个顶部为浅红色,底部为深红色的矩形 我最初的想法是使用上面网站中的代码绘制一个圆角矩形,然后在圆角矩形上覆盖第二个白色到黑色的矩形,使用alpha混合。我试过的每件事最后都在我脸上爆炸了 我见过一些使用numpy的未遂解决方案,但我没有足够的技能将这些代码片段转换为成功的解决方案。如果有人能展示如何修改上面链接中的代码,实现我的叠加思想,或者展示一个在P

我正在尝试使用PIL来绘制一个圆角矩形和颜色的渐变填充。我发现一个很酷的网站()展示了如何绘制一个纯色圆形矩形,我对此很满意,但我希望能够绘制一个顶部为浅红色,底部为深红色的矩形

我最初的想法是使用上面网站中的代码绘制一个圆角矩形,然后在圆角矩形上覆盖第二个白色到黑色的矩形,使用alpha混合。我试过的每件事最后都在我脸上爆炸了

我见过一些使用numpy的未遂解决方案,但我没有足够的技能将这些代码片段转换为成功的解决方案。如果有人能展示如何修改上面链接中的代码,实现我的叠加思想,或者展示一个在Python中获得带有渐变填充的圆角矩形的更好的解决方案,我将不胜感激

干杯,
Ferris

这是一种非常暴力的方法,但它完成了任务。生成渐变的代码是从中借用的

从左到右运行(runTopBottom=False):

从上到下运行(runTopBottom=True):


如果将来有人在寻找一种可以在ImageDraw上进行修补的交钥匙解决方案,我写了以下内容

希望能有帮助

例如: 代码:


对于任何想要更新版本的人来说,这是一个修改版的Whelchel的答案,使用Pillow 7.2.0代替PIL。(我在使用上一版本时遇到问题)

代码:


圆形矩形现在正式在枕头8.2.0中提供,
圆形矩形

从PIL导入图像,ImageDraw
结果=Image.new('RGBA',(100100))
draw=ImageDraw.draw(结果)
绘制圆角矩形((0,0),(100100)),20,fill=“蓝色”)
result.show()


但是,如果需要平滑的,请看一下

蛮力对于我的业余统计实验来说已经足够了。谢谢。我用错了还是怎么了?当我把图像粘贴到另一个图像上时,透明的角变成黑色,内部的角变成黑色color@Jamie粘贴时,将遮罩设置为要粘贴的图像。粘贴(im,box=None,mask=None)嘿,那我该怎么用呢?这正是我需要的`#一个例子:从PIL导入图像,ImageDraw,ImageFont新建图像:Image=Image.new(“RGBA”,size,(255,255,255,0))d:ImageDraw=ImageDraw.Draw(新建图像)d.圆角矩形(xy,圆角半径)`
from PIL import Image, ImageDraw

def channel(i, c, size, startFill, stopFill):
    """calculate the value of a single color channel for a single pixel"""
    return startFill[c] + int((i * 1.0 / size) * (stopFill[c] - startFill[c]))

def color(i, size, startFill, stopFill):
    """calculate the RGB value of a single pixel"""
    return tuple([channel(i, c, size, startFill, stopFill) for c in range(3)])

def round_corner(radius):
    """Draw a round corner"""
    corner = Image.new('RGBA', (radius, radius), (0, 0, 0, 0))
    draw = ImageDraw.Draw(corner)
    draw.pieslice((0, 0, radius * 2, radius * 2), 180, 270, fill="blue")
    return corner

def apply_grad_to_corner(corner, gradient, backwards = False, topBottom = False):
    width, height = corner.size
    widthIter = range(width)

    if backwards:
        widthIter.reverse()

    for i in xrange(height):
        gradPos = 0
    for j in widthIter:
                if topBottom:
                    pos = (i,j)
                else:
                    pos = (j,i)
        pix = corner.getpixel(pos)
            gradPos+=1
        if pix[3] != 0:
            corner.putpixel(pos,gradient[gradPos])

    return corner

def round_rectangle(size, radius, startFill, stopFill, runTopBottom = False):
    """Draw a rounded rectangle"""
    width, height = size
    rectangle = Image.new('RGBA', size)

    if runTopBottom:
      si = height
    else:
      si = width

    gradient = [ color(i, width, startFill, stopFill) for i in xrange(si) ]

    if runTopBottom:
        modGrad = []
        for i in xrange(height):
           modGrad += [gradient[i]] * width
        rectangle.putdata(modGrad)
    else:
        rectangle.putdata(gradient*height)

    origCorner = round_corner(radius)

    # upper left
    corner = origCorner
    apply_grad_to_corner(corner,gradient,False,runTopBottom)
    rectangle.paste(corner, (0, 0))

    # lower left
    if runTopBottom: 
        gradient.reverse()
        backwards = True
    else:
        backwards = False


    corner = origCorner.rotate(90)
    apply_grad_to_corner(corner,gradient,backwards,runTopBottom)
    rectangle.paste(corner, (0, height - radius))

    # lower right
    if not runTopBottom: 
        gradient.reverse()

    corner = origCorner.rotate(180)
    apply_grad_to_corner(corner,gradient,True,runTopBottom)
    rectangle.paste(corner, (width - radius, height - radius))

    # upper right
    if runTopBottom: 
        gradient.reverse()
        backwards = False
    else:
        backwards = True

    corner = origCorner.rotate(270)
    apply_grad_to_corner(corner,gradient,backwards,runTopBottom)
    rectangle.paste(corner, (width - radius, 0))

    return rectangle

img = round_rectangle((200, 200), 70, (255,0,0), (0,255,0), True)
img.save("test.png", 'PNG')
from PIL.ImageDraw import ImageDraw


def rounded_rectangle(self: ImageDraw, xy, corner_radius, fill=None, outline=None):
    upper_left_point = xy[0]
    bottom_right_point = xy[1]
    self.rectangle(
        [
            (upper_left_point[0], upper_left_point[1] + corner_radius),
            (bottom_right_point[0], bottom_right_point[1] - corner_radius)
        ],
        fill=fill,
        outline=outline
    )
    self.rectangle(
        [
            (upper_left_point[0] + corner_radius, upper_left_point[1]),
            (bottom_right_point[0] - corner_radius, bottom_right_point[1])
        ],
        fill=fill,
        outline=outline
    )
    self.pieslice([upper_left_point, (upper_left_point[0] + corner_radius * 2, upper_left_point[1] + corner_radius * 2)],
        180,
        270,
        fill=fill,
        outline=outline
    )
    self.pieslice([(bottom_right_point[0] - corner_radius * 2, bottom_right_point[1] - corner_radius * 2), bottom_right_point],
        0,
        90,
        fill=fill,
        outline=outline
    )
    self.pieslice([(upper_left_point[0], bottom_right_point[1] - corner_radius * 2), (upper_left_point[0] + corner_radius * 2, bottom_right_point[1])],
        90,
        180,
        fill=fill,
        outline=outline
    )
    self.pieslice([(bottom_right_point[0] - corner_radius * 2, upper_left_point[1]), (bottom_right_point[0], upper_left_point[1] + corner_radius * 2)],
        270,
        360,
        fill=fill,
        outline=outline
    )


ImageDraw.rounded_rectangle = rounded_rectangle
def rounded_rectangle(self: ImageDraw, xy, corner_radius, fill=None, outline=None):
    upper_left_point = xy[0]
    bottom_right_point = xy[1]


    self.pieslice([upper_left_point, (upper_left_point[0] + corner_radius * 2, upper_left_point[1] + corner_radius * 2)],
        180,
        270,
        fill=fill,
        outline=outline
    )
    self.pieslice([(bottom_right_point[0] - corner_radius * 2, bottom_right_point[1] - corner_radius * 2), bottom_right_point],
        0,
        90,
        fill=fill,
        outline=outline
    )
    self.pieslice([(upper_left_point[0], bottom_right_point[1] - corner_radius * 2), (upper_left_point[0] + corner_radius * 2, bottom_right_point[1])],
        90,
        180,
        fill=fill,
        outline=outline
    )
    self.pieslice([(bottom_right_point[0] - corner_radius * 2, upper_left_point[1]), (bottom_right_point[0], upper_left_point[1] + corner_radius * 2)],
        270,
        360,
        fill=fill,
        outline=outline
    )
    self.rectangle(
        [
            (upper_left_point[0], upper_left_point[1] + corner_radius),
            (bottom_right_point[0], bottom_right_point[1] - corner_radius)
        ],
        fill=fill,
        outline=fill
    )
    self.rectangle(
        [
            (upper_left_point[0] + corner_radius, upper_left_point[1]),
            (bottom_right_point[0] - corner_radius, bottom_right_point[1])
        ],
        fill=fill,
        outline=fill
    )
    self.line([(upper_left_point[0] + corner_radius, upper_left_point[1]), (bottom_right_point[0] - corner_radius, upper_left_point[1])], fill=outline)
    self.line([(upper_left_point[0] + corner_radius, bottom_right_point[1]), (bottom_right_point[0] - corner_radius, bottom_right_point[1])], fill=outline)
    self.line([(upper_left_point[0], upper_left_point[1] + corner_radius), (upper_left_point[0], bottom_right_point[1] - corner_radius)], fill=outline)
    self.line([(bottom_right_point[0], upper_left_point[1] + corner_radius), (bottom_right_point[0], bottom_right_point[1] - corner_radius)], fill=outline)