2011-10-16 26 views
6

Estoy tratando de usar PIL para dibujar un rectángulo con esquinas redondeadas y un relleno degradado para el color. Encontré un buen sitio web (http://web.archive.org/web/20130306020911/http://nadiana.com/pil-tutorial-basic-advanced-drawing#Drawing_Rounded_Corners_Rectangle) que muestra cómo dibujar un rectángulo redondeado de color sólido y estoy contento con esto, pero quiero ser capaz de dibujar uno que comience de color rojo claro en la parte superior y que pase al rojo oscuro en el fondo.Dibujo de Python Imaging Library (PIL) - Rectángulo redondeado con degradado

Mi idea inicial fue utilizar el código en el sitio web de arriba para dibujar un rectángulo redondeado, y luego superponer un segundo rectángulo de blanco a negro sobre el rectángulo redondeado, usando la mezcla alfa. Todo lo que he intentado termina por explotar en mi cara.

He visto algunas soluciones casi fallidas usando numpy, pero no estoy capacitado para conmutar esos fragmentos de código a una solución exitosa. Agradecería que alguien me mostrara cómo modificar el código en el enlace anterior, implementar mi idea de superposición o mostrar una solución completamente mejor para obtener un rectángulo redondeado con relleno de degradado en Python.

Saludos, Ferris

Respuesta

12

Se trata de un método de fuerza bruta muy, pero hace el trabajo. El código para producir los degradados se tomó prestado del 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') 

de izquierda a derecha (runTopBottom = False):

enter image description here

que corre de arriba a abajo (runTopBottom = true):

enter image description here

+0

fuerza bruta es buena suficiente para mi experimento de estadística amateur. Gracias. – ferris

Cuestiones relacionadas