DrawCV
A clean, extensible, object-oriented 2D drawing engine and graphics library built on OpenCV and NumPy as the raster rendering backend.
Unlike immediate-mode OpenCV functions (cv2.line, cv2.rectangle, cv2.circle) that permanently alter pixels in-place, DrawCV operates on a strict retained-mode graphics architecture. Every drawn object remains addressable, editable, movable, transformable, hideable, reorderable, and re-renderable after creation.
Drawable Entities ───► Scene Graph ───► OpenCVRenderer ───► Canvas Buffer
(Object Model) (Authoritative) (Centralized AA (NumPy / OpenCV)
& Compositing)
Key Architectural Principles
- Retained-Mode Graphics: The
Sceneis authoritative. The raster image is purely disposable and reproducible upon re-rendering. Mutating an object's properties in place and invoking.render()regenerates the scene without manual pixel clearing or damage rect calculations. - Decoupled Primitives (Zero OpenCV in Shapes):
Line,Rectangle, andCircledo not import or callcv2. All rasterization, OpenCV calls, coordinate quantization, and alpha compositing are centralized strictly insideOpenCVRenderer. - Immutable Value Objects:
Pointis an immutable@dataclass(frozen=True)with vector arithmetic.ColorandBoundingBoxenforce strict validation (no silent clamping of invalid channel or dimension values). - Clean Geometry Ownership:
Sceneowns logical dimensions (width,height) andbackground.Canvasowns the resulting BGR NumPy array. - Exact Alpha Compositing: Translucent strokes and fills are blended mathematically: $$\text{effective_alpha} = \text{color.a} \times \text{style.opacity} \times \text{drawable.opacity}$$ $$\text{dst} = \text{src} \cdot \alpha + \text{dst} \cdot (1 - \alpha)$$
- No Silent Unsupported Behavior: Unimplemented transforms (e.g. arbitrary rotation of rectangles or non-uniform scaling) raise
RenderErrorrather than silently failing to render.
Installation
Install via pip from PyPI:
pip install pydrawcv
Or install from source for development:
git clone https://github.com/nuhyamin1/drawcv.git
cd drawcv
pip install -e ".[dev]"
Coordinate System
DrawCV uses standard computer graphics screen coordinates:
- Origin
(0, 0): Top-left corner of the canvas. - +X axis: Extends horizontally to the right.
- +Y axis: Extends vertically downward.
- Subpixel Precision: Model geometry is stored as floating-point numbers (
Point(120.35, 440.81)). The renderer is responsible for coordinate quantization and anti-aliasing during rasterization.
Quickstart Example
from drawcv import (
Scene,
OpenCVRenderer,
Point,
Color,
Circle,
Line,
Rectangle,
StrokeStyle,
FillStyle,
)
# 1. Create a retained Scene
scene = Scene(width=1200, height=800, background=Color.white())
# 2. Add shapes
circle = Circle(
center=Point(400, 300),
radius=100,
stroke=StrokeStyle(color=Color.black(), width=4.0),
fill=FillStyle(color=Color.from_hex("#73B9FF"), opacity=0.5)
)
line = Line(
start=Point(100, 100),
end=Point(800, 500),
stroke=StrokeStyle(color=Color.red(), width=5.0)
)
rectangle = Rectangle(
position=Point(700, 150),
width=220,
height=150,
stroke=StrokeStyle(color=Color.black(), width=3.0),
fill=FillStyle(color=Color.green(), opacity=0.4)
)
scene.add(circle)
scene.add(line)
scene.add(rectangle)
# 3. Retained-mode in-place manipulation
circle.center = Point(500, 350)
circle.radius = 130
line.stroke.color = Color.blue()
rectangle.width = 280
# 4. Render to Canvas
renderer = OpenCVRenderer()
canvas = renderer.render(scene)
# 5. Export to disk
canvas.save("output.png")
Core Components (Phase 1)
Geometry & Color
Point(x, y): Immutable 2D vector supporting+,-,*,/,.translate(dx, dy),.distance_to(other).Color(r, g, b, a=1.0): RGBA color model with.from_hex(),.from_rgb(),.from_bgr(),.to_bgr(),.to_hex(),.black(),.white(),.red(), etc.BoundingBox(x, y, width, height): Spatial bounding box withleft,right,top,bottom,center,corners,.contains(),.intersects(),.union(),.expand().
Styling
StrokeStyle(color, width, opacity, line_type): Anti-aliased stroke styling (LineType.AA,LINE_8,LINE_4).FillStyle(enabled, color, opacity): Interior shape fill styling.
Shapes
Line(start, end, stroke): Computeslength,angle,center, and stroke-aware bounds.Rectangle(position, width, height, stroke, fill): Computesarea,center,corners, and stroke-aware bounds.Circle(center, radius, stroke, fill): Computesdiameter,area,circumference, and stroke-aware bounds.
Advanced Geometry & Manipulation (Phases 2 & 3)
- Transforms & Manipulation:
.move(dx, dy),.rotate(deg, pivot),.scale(sx, sy, pivot),.clone(), exact geometric hit-testing. - Advanced Shapes:
Ellipse,Arc(OPEN, CHORD, PIE),Polygon,Polyline,Arrow(TRIANGLE, OPEN, DIAMOND, CIRCLE heads),BezierCurve(quadratic and cubic),Path(retained vector path withMoveTo,LineTo,QuadraticTo,CubicTo,Close), andRoundedRectangle. - Topological Fill Rules:
FillRule.EVEN_ODDandFillRule.NON_ZEROevaluation.
Scene System (Phase 4)
- Hierarchical Groups (
Group): Container drawables supporting nested groups, cascaded transforms, non-destructive coordinate propagation, zero-shift world-transform reparenting, and collective world AABB computation. - Rendering Layers (
Layer): Global rendering passes and stack organization (z_order), visibility, opacity, and cascading locked state. - Logical Selection (
Selection): Multi-object selection controller with ancestor/descendant normalization (preventing double-transforms), rigid rotation around collective bounds center, scaling, batch property adjustments, and container-safe.group(). - Declarative Relative Positioning:
align_left,align_right,align_top,align_bottom,align_center_x,align_center_y,align_centers,place_above,place_below,place_left_of,place_right_of(with defaultgap=20.0),distribute_horizontally,distribute_vertically. - Authoritative Scene Registry & Query: Fast $O(1)$ lookup via
scene.get(id)across layers and groups, collision prevention,find_by_name,find_by_tag,find_by_type,find_by_metadata, and predicate searches.
Freehand Engine (Phase 5)
StrokePoint: Immutable frozen point holding coordinates with physical capture metadata (pressure,timestamp,velocity).FreehandStroke: Retained-mode freehand stroke retaining authoritative raw sampled input points without mutation.- Modular Path Processing Pipeline:
- RDP Simplification (
rdp_simplify): Noise and redundant point reduction while preserving salient corners and all metadata. - Chaikin Smoothing (
chaikin_smooth): Iterative corner-cutting curve refinement with open endpoint preservation. - Catmull-Rom Spline (
catmull_rom_spline): $C^1$-continuous cubic spline passing exactly through control points with centripetal parameterization ($\alpha=0.5$). - Linear Metadata Interpolation: Clamped linear interpolation for pressure $[0.0, 1.0]$ and timestamps preventing overshoot and preserving physical monotonicity.
- RDP Simplification (
- Variable-Width Contour Rasterization: Segment-normal tapered quadrilateral ribbons with circular joint/cap discs for stylus calligraphy (pressure-sensitive) and fountain pen flick dynamics (velocity-sensitive).
Compositing & Effects (Phase 6)
-
Isolated Offscreen Surfaces: Eliminates overlapping-geometry opacity accumulation by rasterizing translucent groups and layers to isolated premultiplied float32 BGRA buffers.
-
Single-Application Opacity Boundary: Ancestor opacity is withheld during isolated subtree rendering and applied strictly once at the compositing boundary.
-
Premultiplied Alpha Pipeline: Mathematically rigorous blending ($C_{\text{out}} = C_s + C_d(1 - \alpha_s)$, $\alpha_{\text{out}} = \alpha_s + \alpha_d(1 - \alpha_s)$) with 4-channel synchronous scaling across B, G, R, and A to prevent color fringing.
-
Effects:
BlurEffect: Content blur (BlurType.GAUSSIAN,BlurType.BOX) executed on premultiplied intermediates without boundary halos.ShadowEffect: Cast shadows with signed asymmetric offsets (offset_x,offset_y), blur radius, and shadow color, rendered behind base geometry.- Effect-Inflated Buffers: Asymmetric buffer expansion accommodating signed shadow offsets and blur penumbras.
-
Clipping & Masking:
ClipRect&ClipPath: Vector stencils applied as the final post-effects clipping boundary.Mask: Grayscale luminance/alpha masks withMaskMapping.FIT_BOUNDSmapped against pre-effect visual bounds.
-
New Retained Primitives:
ImageObject: Raster images supporting BGR and BGRA, source cropping, target sizing, affine warps, and alpha compositing.Text: Typography with font families (FontFamily.SANS_SERIF,SERIF,MONOSPACE,SCRIPT), alignments (LEFT,CENTER,RIGHT), and background plates with optionalbackground_radius.
-
Phase 7 Capabilities (Persistence & History Engine):
- Canonical JSON Document Envelope: Root header (
{"format": "drawcv", "version": "1.0", "scene": ...}) with bit-for-bit deterministic serialization (sort_keys=True,allow_nan=False). - Strict Version Migration Pipeline:
SchemaMigratorenables sequential forward migrations for backward compatibility across schema versions. - Structured Raster Payload: Lossless PNG base64 encoding with decoded shape and
uint8dtype validation forMaskandImageObject. - Lossless Float Alpha: Colors serialize alpha as exact floating-point numbers (
0.5 == 0.5), preventing 8-bit quantization drift. - In-Place Live Object Identity Preservation: History undo/redo mutates existing live Python instances via
_apply_semantic_state(), preserving references (scene.get(id) is original_obj). - Recursive Group Semantic Snapshots:
Group._get_semantic_state()captures descendant states and ordering;Group._apply_semantic_state()restores states in-place. - Reversible Operations:
add,remove,move_to_front,move_to_back,move_forward,move_backward,group,ungroup,move_object,rotate_object,scale_object,restyle_object,with scene.edit(...), andwith scene.batch(...). - History Invariants: Automatic redo branch invalidation, no-op edit filtering, exception rollback, and drift-free 50-cycle undo/redo.
- Canonical JSON Document Envelope: Root header (
-
Phase 8 Capabilities (Temporal Drawing & Animation Engine):
- Timing & Pacing Model: Dedicated
Timingvalue object controllingstart_time,duration,delay,speed, andloop, with clampedget_progress()for progressive reveal and rawevaluate()for property tracks. - Easing Suite: 22 standard easing curves across Linear, Quadratic, Cubic, Sine, Exponential, Circular, Elastic, and Bounce families.
- Arc-Length Progressive Path Slicing: True Euclidean path-length parameterization for
Line,Polyline,Arrow,BezierCurve,Path,FreehandStroke, andArc(sweep angle reveal). - Stroke-First Reveal Semantics: While
render_progress < 1.0, shapes progressively expose outline stroke only; interior fills are suppressed until reaching full completion ($p = 1.0$). - Explicit Progressive Capability:
supports_progressive_renderingprevents slicing recursion and ensures non-path shapes (e.g.Rectangle,Circle) render safely. - Observational Non-Destructive Sampling:
scene.render_at_time(t)evaluates timestamps with suspended history and unconditionally restores authored state infinally, preserving live object identity and preventing history pollution. - Automatic Timing Binding:
drawable.timingautomatically drivesdrawable.render_progressduring temporal evaluation without requiring explicit Timeline tracks. - Synchronized Timeline: Multi-track property animations with deterministic insertion-order conflict resolution and comprehensive
scene.temporal_durationderivation. - Typed Value Serialization:
AnimationTrackpersists typed value codecs ("number","point","color","transform","bounds") and string-only easing contracts. - Document Schema 1.1 & Migration: Automatic forward migration from Phase 7 (
"1.0") to"1.1", injecting temporal defaults across layers and nested groups. - Multi-Frame & Video Export:
VideoRendererencoding playable MP4 video via OpenCVcv2.VideoWriter, image sequences, and optional Pillow animated GIF.
- Timing & Pacing Model: Dedicated
Running Tests & Demos
Run automated unit tests (240 tests, 100% green):
pytest tests/ -v
Run visual demonstrations:
python examples/phase1_demo.py
python examples/phase2_demo.py
python examples/phase3_demo.py
python examples/phase4_demo.py
python examples/phase5_demo.py
python examples/phase6_demo.py
python examples/phase7_demo.py
python examples/progressive_drawing.py
python examples/phase8_demo.py
Generated outputs will be saved to examples/output/.
Development Roadmap
- Phase 1 — Foundation: Retained scene graph, Point, Color, BoundingBox, Line, Rectangle, Circle, StrokeStyle, FillStyle, OpenCVRenderer, Canvas, true alpha compositing, unit tests, visual demos.
- Phase 2 — Manipulation: Full affine transform rendering (rotation, non-uniform scaling), object cloning, hit testing.
- Phase 3 — Advanced Geometry: Ellipse, Arc, Polygon, Polyline, Arrow, Bézier curves, General Path, RoundedRectangle.
- Phase 4 — Scene System: Semantic Groups, Rendering Layers, Selection models, Relative positioning utilities, Centralized scene registry.
- Phase 5 — Freehand Engine: FreehandStroke, StrokePoint, Chaikin smoothing, Ramer-Douglas-Peucker simplification, Catmull-Rom interpolation, pressure and velocity sensitive variable width.
- Phase 6 — Compositing & Effects: Grayscale masks, clipping rectangles, clipping paths, ImageObject, Text, blur, drop shadows, isolated group/layer offscreen compositing.
- Phase 7 — Persistence & History: Strict canonical JSON serialization, forward schema migration, command-based Undo/Redo engine, live identity preservation, recursive group state snapshots.
- Phase 8 — Temporal Drawing & Animation: Timing metadata, arc-length progressive rendering, stroke-first reveal, 22 easing curves, non-destructive temporal sampling, Timeline multi-track synchronization, schema 1.1 migration, OpenCV MP4 video encoding.
Metadata
Release files for pydrawcv 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pydrawcv-0.1.0.tar.gz | 155.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pydrawcv-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 299.9 kB
Release files / pydrawcv-0.1.0.tar.gz
| Download URL | pydrawcv-0.1.0.tar.gz |
|---|---|
| Size | 155.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
50d57754b27403f86ce61a324baacec47887a47ff883acdbea9cc170a83b23b9
|
|
BLAKE2b-256 checksum How to use checksums |
0fb9f1115b8b09ab82a33144033ad3e516586814c01b4f8374dca9fe3f7dd723
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.2
|
Release files / pydrawcv-0.1.0-py3-none-any.whl
| Download URL | pydrawcv-0.1.0-py3-none-any.whl |
|---|---|
| Size | 144.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6258a78f1481f55d46ce808e5006396dd1e387df512252d81ea81542d0209ce2
|
|
BLAKE2b-256 checksum How to use checksums |
b6cc733794562714f8d4f160673218afe1f85f62e4e6b6bd3c4cc6a51999b42b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.2
|