Spaces:
Running
Running
File size: 1,774 Bytes
a5ff880 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
from PIL import Image, ImageDraw
def draw_smooth_ellipse(base_img, bbox, fill=None, outline=None, width=1, scale=4):
"""Draw an anti-aliased ellipse on top of `base_img`.
This function creates a larger temporary overlay at `scale` times the
base size, draws the ellipse there, downsamples with LANCZOS and
composites it onto the base image. This produces much smoother edges.
Args:
base_img (PIL.Image): RGBA image to draw onto. Returned image is a new
Image object (alpha-composited).
bbox (sequence): [x0, y0, x1, y1] bounding box in base image coordinates.
fill (tuple|str): Fill color (RGBA tuple or PIL color).
outline (tuple|str): Outline color.
width (int): Outline width in base-image pixels.
scale (int): Supersampling factor. 3-6 is usually good. Default 4.
Returns:
PIL.Image: New RGBA image with the ellipse composited.
"""
if base_img.mode != 'RGBA':
base_img = base_img.convert('RGBA')
w, h = base_img.size
# Create large transparent overlay
overlay_large = Image.new('RGBA', (w * scale, h * scale), (0, 0, 0, 0))
draw_large = ImageDraw.Draw(overlay_large)
x0, y0, x1, y1 = bbox
bbox_large = [int(x0 * scale), int(y0 * scale), int(x1 * scale), int(y1 * scale)]
if fill:
draw_large.ellipse(bbox_large, fill=fill)
if outline and width and width > 0:
draw_large.ellipse(bbox_large, outline=outline, width=max(1, int(width * scale)))
# Downsample overlay to original size with LANCZOS (antialiasing)
overlay_small = overlay_large.resize((w, h), Image.Resampling.LANCZOS)
# Composite overlay onto base image
result = Image.alpha_composite(base_img, overlay_small)
return result
|