Pillow technical diagrams
Create technical poster and diagram images using Pillow (PIL), including shapes, text, lines, and layered composition.From its SKILL.md
npx -y skills add cxcscmu/SkillLearnBench --skill pillow-technical-diagramsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
2.6 KB, 741 tokens by cl100k_base, as published. Nobody here has run it
Pillow Technical Diagrams
Installation
pip install Pillow numpy --break-system-packages
Core Setup
from PIL import Image, ImageDraw, ImageFont
import numpy as np
# Create canvas
W, H = 2400, 3200 # portrait poster
img = Image.new("RGB", (W, H), color="#F5F0E8")
draw = ImageDraw.Draw(img)
Drawing Shapes
# Rectangle with rounded corners (Pillow 9+)
draw.rounded_rectangle([x0,y0,x1,y1], radius=12, fill="#hex", outline="#hex", width=2)
# Ellipse / circle
draw.ellipse([x0,y0,x1,y1], fill="#hex", outline="#hex", width=1)
# Polygon
draw.polygon([(x1,y1),(x2,y2),(x3,y3)], fill="#hex", outline="#hex")
# Line with width
draw.line([(x0,y0),(x1,y1)], fill="#hex", width=2)
Text Rendering
# Load system font (fallback chain)
import os
def load_font(size, bold=False):
candidates = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" if bold else "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf" if bold else "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
"/usr/share/fonts/truetype/freefont/FreeSansBold.ttf" if bold else "/usr/share/fonts/truetype/freefont/FreeSans.ttf",
]
for path in candidates:
if os.path.exists(path):
return ImageFont.truetype(path, size)
return ImageFont.load_default()
font_title = load_font(120, bold=True)
draw.text((x, y), "NOVA", fill="#1A1A1A", font=font_title)
Centered / Anchored Text
# Anchor options: "lt" (left-top), "mm" (middle-middle), "rt" (right-top)
draw.text((cx, cy), "label", fill="#hex", font=font, anchor="mm")
# Get bounding box for manual centering
bbox = draw.textbbox((0,0), "text", font=font)
tw = bbox[2] - bbox[0]
th = bbox[3] - bbox[1]
draw.text((cx - tw//2, cy - th//2), "text", fill="#hex", font=font)
Saving
img.save("/root/output.png", dpi=(300, 300))
Alpha / Compositing
layer = Image.new("RGBA", (W, H), (0,0,0,0))
d = ImageDraw.Draw(layer)
d.rectangle([...], fill=(200,200,200,120)) # semi-transparent
img_rgba = img.convert("RGBA")
img_rgba = Image.alpha_composite(img_rgba, layer)
img = img_rgba.convert("RGB")
Tips
- Use
draw.linewithwidth=1for fine annotation leader lines. - Build exploded layers from bottom to top in draw order.
- Use
numpyfor computing evenly-spaced offsets along an explode axis. - For dashed lines, draw segments manually in a loop.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.