我正在尝试使用PIL绘制一个带圆角的矩形和一个渐变填充颜色。我发现了一个很酷的网站(http://web.archive.org/web/20130306020911/http://nadiana.com/pil-tutorial-basic-advanced-drawing#Drawing_Rounded_Corners_Rectangle),它展示了如何绘制一个纯色圆角矩形,我对此很满意,但我希望能够在顶部绘制一个浅红色的网站并转到底部是深红色。
我最初的想法是使用上面网站中的代码绘制圆角矩形,然后使用Alpha混合在圆角矩形上覆盖第二个白色到黑色矩形。我尝试过的所有东西都会在我的脸上爆炸。
我已经看到了使用numpy的一些近乎未解决的解决方案,但我不够熟练将这些代码片段转换为成功的解决方案。如果有人能够展示如何修改上面链接中的代码,实现我的叠加想法,或者展示一个完全更好的解决方案来获得Python中带渐变填充的圆角矩形,我将不胜感激。
干杯, 摩天
答案 0 :(得分:13)
这是一种非常强力的方法,但它完成了工作。生成渐变的代码来自here。
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')
从左向右运行(runTopBottom = False):
从上到下运行(runTopBottom = True):
答案 1 :(得分:6)
如果将来某人正在寻找一个可以在ImageDraw上修补的更多交钥匙解决方案,我写了以下内容。
希望它有所帮助。
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
答案 2 :(得分:2)
对于正在寻找更新版本的任何人,这都是使用Pillow 7.2.0而不是PIL的Whelchel答案的修改版本。 (我在使用旧版本的轮廓时遇到了问题)
代码:
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)
答案 3 :(得分:0)
Rounded rect 现在正式在 Pillow 8.2.0 中提供,rounded_rectangle
https://github.com/python-pillow/Pillow/pull/5208
from PIL import Image, ImageDraw
result = Image.new('RGBA', (100, 100))
draw = ImageDraw.Draw(result)
draw.rounded_rectangle(((0, 0), (100, 100)), 20, fill="blue")
result.show()
如果需要平滑,请查看 https://github.com/python-pillow/Pillow/issues/4765