Python Imaging Library (PIL) Drawing - Rounded Rectangle with Gradient

I am trying to use PIL to draw a rounded rectangle and fill a gradient for color. I found a cool website ( http://web.archive.org/web/20130306020911/http://nadiana.com/pil-tutorial-basic-advanced-drawing#Drawing_Rounded_Corners_Rectangle ) that shows how to draw a solid rectangle with solid color, and I'm happy with that, but I want to be able to draw one that starts light red on top, and below it turns dark red.

My initial thought was to use the code on the website above to draw a rounded rectangle, and then lay a second white in the black rectangle above the rounded rectangle using alpha blending. Everything I tried ends with an explosion in my face.

I saw some skipped solutions using numpy, but I'm not qualified enough to bring these code snippets to a successful solution. I would appreciate it if someone could show how to change the code in the link above, implement my idea of ​​overlay, or show a completely better solution for getting a rounded rectangle with a gradient fill in Python.

Cheers, Ferris

+6
source share
2 answers

This method is very brute force, but it does its job. The code for creating gradients was borrowed from 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') 

Run from left to right (runTopBottom = False):

enter image description here

Run top to bottom (runTopBottom = True):

enter image description here

+12
source

In case someone in the future is looking for a little more turnkey solutions that can be defused on ImageDraw, I wrote the following.

Hope this helps.

Example: enter image description here The code:

 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
source

Source: https://habr.com/ru/post/899413/


All Articles