import webcolors
from PIL import Image, ImageDraw
from pydantic import Field
from todays_paper_web.widgets import registerView, View
from todays_paper_web.widgets.params import Color
from todays_paper_web.widgets.view import ViewParams
# Pillow's rounded_rectangle corners order: (top-left, top-right, bottom-right, bottom-left).
_CORNER_GROUPS = {
"all": ("tl", "tr", "br", "bl"),
"none": (),
"top": ("tl", "tr"),
"bottom": ("bl", "br"),
"left": ("tl", "bl"),
"right": ("tr", "br"),
}
def _parseCorners(value):
if not value:
return (True, True, True, True)
names = set()
for token in value.split(","):
token = token.strip().lower()
names.update(_CORNER_GROUPS.get(token, (token,)))
return tuple(name in names for name in ("tl", "tr", "br", "bl"))
[docs]
class RectangleParams(ViewParams):
width: int = Field(1, description="Rectangle width in pixels.")
height: int = Field(1, description="Rectangle height in pixels.")
color: Color = Field(
default_factory=lambda: webcolors.name_to_rgb("black"),
description="Fill color (if `fill` is set) or outline color otherwise.",
)
fill: bool = Field(
False, description="Fill the rectangle with `color` instead of just outlining it."
)
radius: int = Field(
0, description="Corner radius in pixels; 0 draws sharp corners."
)
corners: str = Field(
"all",
description="Which corners `radius` rounds: `all`, `none`, `top`, `bottom`, `left`, "
"`right`, or a comma-separated list of `tl`/`tr`/`br`/`bl`.",
)
@registerView("rectangle")
class RectangleView(View):
Params = RectangleParams
def render(self):
img = Image.new("RGBA", (self.params.width, self.params.height), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
box = (0, 0, self.params.width - 1, self.params.height - 1)
if self.params.radius > 0:
draw.rounded_rectangle(
box,
radius=self.params.radius,
fill=self.params.color if self.params.fill else None,
outline=self.params.color,
corners=_parseCorners(self.params.corners),
)
else:
draw.rectangle(
box, fill=self.params.color if self.params.fill else None, outline=self.params.color
)
return img