2011-10-16 119 views
6

我想用PIL绘制带圆角的矩形和渐变填充颜色。我找到了一个很酷的网站(http://web.archive.org/web/20130306020911/http://nadiana.com/pil-tutorial-basic-advanced-drawing#Drawing_Rounded_Corners_Rectangle),它展示了如何绘制一个纯色的圆角矩形,我对此感到满意,但是我希望能够绘制一个从顶部开始点亮红色并在底部。Python成像库(PIL)绘图 - 带有渐变的圆角矩形

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

我已经看到了一些使用numpy的几乎未命中的解决方案,但我不够熟练,无法将这些代码片段转换为成功的解决方案。如果有人能够展示如何修改上面链接中的代码,实现我的覆盖思路,或者展示一个完全更好的解决方案,以获得带有渐变填充Python的圆角矩形,我将不胜感激。

干杯, 摩天

回答

12

这是一个非常强力的方法,但它能够完成任务。产生梯度的代码是从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):

enter image description here

从顶端运行至底部(runTopBottom = TRUE):

enter image description here

+0

蛮力是好的足够用于我的业余统计实验。谢谢。 – ferris