Replace batch DAG system with streaming architecture
- Remove legacy_tasks.py, hybrid_state.py, render.py - Remove old task modules (analyze, execute, execute_sexp, orchestrate) - Add streaming interpreter from test repo - Add sexp_effects with primitives and video effects - Add streaming Celery task with CID-based asset resolution - Support both CID and friendly name references for assets - Add .dockerignore to prevent local clones from conflicting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
136
sexp_effects/primitive_libs/drawing.py
Normal file
136
sexp_effects/primitive_libs/drawing.py
Normal file
@@ -0,0 +1,136 @@
|
||||
"""
|
||||
Drawing Primitives Library
|
||||
|
||||
Draw shapes, text, and characters on images.
|
||||
"""
|
||||
import numpy as np
|
||||
import cv2
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
|
||||
# Default font (will be loaded lazily)
|
||||
_default_font = None
|
||||
|
||||
|
||||
def _get_default_font(size=16):
|
||||
"""Get default font, creating if needed."""
|
||||
global _default_font
|
||||
if _default_font is None or _default_font.size != size:
|
||||
try:
|
||||
_default_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", size)
|
||||
except:
|
||||
_default_font = ImageFont.load_default()
|
||||
return _default_font
|
||||
|
||||
|
||||
def prim_draw_char(img, char, x, y, font_size=16, color=None):
|
||||
"""Draw a single character at (x, y)."""
|
||||
if color is None:
|
||||
color = [255, 255, 255]
|
||||
|
||||
pil_img = Image.fromarray(img)
|
||||
draw = ImageDraw.Draw(pil_img)
|
||||
font = _get_default_font(font_size)
|
||||
draw.text((x, y), char, fill=tuple(color), font=font)
|
||||
return np.array(pil_img)
|
||||
|
||||
|
||||
def prim_draw_text(img, text, x, y, font_size=16, color=None):
|
||||
"""Draw text string at (x, y)."""
|
||||
if color is None:
|
||||
color = [255, 255, 255]
|
||||
|
||||
pil_img = Image.fromarray(img)
|
||||
draw = ImageDraw.Draw(pil_img)
|
||||
font = _get_default_font(font_size)
|
||||
draw.text((x, y), text, fill=tuple(color), font=font)
|
||||
return np.array(pil_img)
|
||||
|
||||
|
||||
def prim_fill_rect(img, x, y, w, h, color=None):
|
||||
"""Fill a rectangle with color."""
|
||||
if color is None:
|
||||
color = [255, 255, 255]
|
||||
|
||||
result = img.copy()
|
||||
x, y, w, h = int(x), int(y), int(w), int(h)
|
||||
result[y:y+h, x:x+w] = color
|
||||
return result
|
||||
|
||||
|
||||
def prim_draw_rect(img, x, y, w, h, color=None, thickness=1):
|
||||
"""Draw rectangle outline."""
|
||||
if color is None:
|
||||
color = [255, 255, 255]
|
||||
|
||||
result = img.copy()
|
||||
cv2.rectangle(result, (int(x), int(y)), (int(x+w), int(y+h)),
|
||||
tuple(color), thickness)
|
||||
return result
|
||||
|
||||
|
||||
def prim_draw_line(img, x1, y1, x2, y2, color=None, thickness=1):
|
||||
"""Draw a line from (x1, y1) to (x2, y2)."""
|
||||
if color is None:
|
||||
color = [255, 255, 255]
|
||||
|
||||
result = img.copy()
|
||||
cv2.line(result, (int(x1), int(y1)), (int(x2), int(y2)),
|
||||
tuple(color), thickness)
|
||||
return result
|
||||
|
||||
|
||||
def prim_draw_circle(img, cx, cy, radius, color=None, thickness=1, fill=False):
|
||||
"""Draw a circle."""
|
||||
if color is None:
|
||||
color = [255, 255, 255]
|
||||
|
||||
result = img.copy()
|
||||
t = -1 if fill else thickness
|
||||
cv2.circle(result, (int(cx), int(cy)), int(radius), tuple(color), t)
|
||||
return result
|
||||
|
||||
|
||||
def prim_draw_ellipse(img, cx, cy, rx, ry, angle=0, color=None, thickness=1, fill=False):
|
||||
"""Draw an ellipse."""
|
||||
if color is None:
|
||||
color = [255, 255, 255]
|
||||
|
||||
result = img.copy()
|
||||
t = -1 if fill else thickness
|
||||
cv2.ellipse(result, (int(cx), int(cy)), (int(rx), int(ry)),
|
||||
angle, 0, 360, tuple(color), t)
|
||||
return result
|
||||
|
||||
|
||||
def prim_draw_polygon(img, points, color=None, thickness=1, fill=False):
|
||||
"""Draw a polygon from list of [x, y] points."""
|
||||
if color is None:
|
||||
color = [255, 255, 255]
|
||||
|
||||
result = img.copy()
|
||||
pts = np.array(points, dtype=np.int32).reshape((-1, 1, 2))
|
||||
|
||||
if fill:
|
||||
cv2.fillPoly(result, [pts], tuple(color))
|
||||
else:
|
||||
cv2.polylines(result, [pts], True, tuple(color), thickness)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
PRIMITIVES = {
|
||||
# Text
|
||||
'draw-char': prim_draw_char,
|
||||
'draw-text': prim_draw_text,
|
||||
|
||||
# Rectangles
|
||||
'fill-rect': prim_fill_rect,
|
||||
'draw-rect': prim_draw_rect,
|
||||
|
||||
# Lines and shapes
|
||||
'draw-line': prim_draw_line,
|
||||
'draw-circle': prim_draw_circle,
|
||||
'draw-ellipse': prim_draw_ellipse,
|
||||
'draw-polygon': prim_draw_polygon,
|
||||
}
|
||||
Reference in New Issue
Block a user