Release NaraMotion v0.26.0: Structure of Arrays (SoA), Path Arena Allocator, Uniform Grid Indexing, Dual-Buffer Rendering & Centroid Spring Pop-in
b516e00 verified Download tests/test_v2_features.py from ArifiIslam/NaraMotion: direct link, hf CLI and curl.
- Browser
- Download file 4.37 kB
-
https://huggingface.co/ArifiIslam/NaraMotion/resolve/main/tests/test_v2_features.py
- Command line
-
hf download hf://ArifiIslam/NaraMotion/tests/test_v2_features.py
-
curl -L -o test_v2_features.py https://huggingface.co/ArifiIslam/NaraMotion/resolve/main/tests/test_v2_features.py
4.37 kB
| import math | |
| import os | |
| import pytest | |
| import numpy as np | |
| import naramotion | |
| from naramotion import ( | |
| Image, Context, Format, Path, Font, Rect, Box, Point, Matrix2D, | |
| StrokeCap, StrokeJoin, StrokeTransformOrder, FlattenMode, | |
| RenderingQuality, GradientQuality, PatternQuality, | |
| LinearGradient, RadialGradient, SvgContext, export_svg | |
| ) | |
| from tests.test_font import get_system_font_path | |
| def test_context_threading(): | |
| img = Image(800, 600, Format.PRGB32) | |
| with Context(img, thread_count=4) as ctx: | |
| assert ctx.thread_count == 4 | |
| ctx.fill_all("black") | |
| for i in range(100): | |
| ctx.fill_circle(i * 8, 300, 20, "cyan") | |
| assert img.width == 800 | |
| def test_state_cookie_save_restore(): | |
| img = Image(400, 400, Format.PRGB32) | |
| with Context(img) as ctx: | |
| ctx.translate(100, 100) | |
| cookie = ctx.save_with_cookie() | |
| ctx.scale(2.0, 2.0) | |
| ctx.restore(cookie) | |
| def test_asymmetric_stroke_caps(): | |
| img = Image(300, 300, Format.PRGB32) | |
| with Context(img) as ctx: | |
| ctx.stroke_width = 10.0 | |
| ctx.set_stroke_start_cap(StrokeCap.BUTT) | |
| ctx.set_stroke_end_cap(StrokeCap.ROUND) | |
| ctx.stroke_line(50, 150, 250, 150, "white") | |
| def test_stroke_transform_order(): | |
| img = Image(300, 300, Format.PRGB32) | |
| with Context(img) as ctx: | |
| ctx.stroke_transform_order = StrokeTransformOrder.BEFORE | |
| ctx.stroke_transform_order = StrokeTransformOrder.AFTER | |
| def test_flatten_and_quality_hints(): | |
| img = Image(300, 300, Format.PRGB32) | |
| with Context(img) as ctx: | |
| ctx.rendering_quality = RenderingQuality.ANTIALIAS | |
| ctx.gradient_quality = GradientQuality.DITHER | |
| ctx.pattern_quality = PatternQuality.BILINEAR | |
| ctx.set_flatten_tolerance(0.25) | |
| assert ctx.flatten_tolerance == 0.5 or ctx.flatten_tolerance > 0 | |
| def test_chord_and_pie_primitives(): | |
| img = Image(500, 500, Format.PRGB32) | |
| with Context(img) as ctx: | |
| ctx.fill_all("#090D16") | |
| # 1. Pie slice (5 args: cx, cy, r, start, sweep) | |
| ctx.fill_pie(150, 150, 100, 0.0, math.pi * 0.75, style="#38BDF8") | |
| ctx.stroke_pie(150, 150, 100, 0.0, math.pi * 0.75, style="white") | |
| # 2. Chord segment (6 args: cx, cy, rx, ry, start, sweep) | |
| ctx.fill_chord(350, 150, 100, 80, 0.0, math.pi, style="#EC4899") | |
| ctx.stroke_chord(350, 150, 100, 80, 0.0, math.pi, style="yellow") | |
| def test_path_length_vertices_and_svg_d(): | |
| p = Path() | |
| p.move_to(0, 0) | |
| p.line_to(100, 0) | |
| p.line_to(100, 100) | |
| p.close() | |
| assert p.get_vertex_count() == 4 | |
| cmd, x, y = p.get_vertex(1) | |
| assert (x, y) == (100.0, 0.0) | |
| vertices = p.get_vertices() | |
| assert len(vertices) == 4 | |
| # Triangle perimeter = 100 + 100 + sqrt(100^2 + 100^2) ≈ 341.42 | |
| length = p.get_length() | |
| assert 340.0 <= length <= 343.0 | |
| d_str = p.to_svg_d() | |
| assert "M 0.000 0.000" in d_str | |
| assert "L 100.000 0.000" in d_str | |
| assert "Z" in d_str | |
| def test_svg_exporter_module(): | |
| svg_ctx = SvgContext(width=800, height=600, title="NaraMotion Test SVG") | |
| svg_ctx.fill_all("#0F172A") | |
| svg_ctx.fill_circle(400, 300, 150, style="#38BDF8") | |
| svg_ctx.stroke_round_rect(100, 100, 200, 120, rx=20, ry=20, style="white") | |
| p = Path() | |
| p.move_to(50, 50).line_to(200, 50).quad_to(300, 100, 200, 200).close() | |
| svg_ctx.fill_path(p, style="#EC4899") | |
| svg_str = svg_ctx.to_svg() | |
| assert "<svg" in svg_str | |
| assert "viewBox=\"0 0 800 600\"" in svg_str | |
| assert "<circle" in svg_str | |
| assert "<path" in svg_str | |
| out_file = "test_export.svg" | |
| export_svg(svg_ctx, out_file) | |
| assert os.path.exists(out_file) | |
| if os.path.exists(out_file): | |
| os.remove(out_file) | |
| def test_clip_to_path_and_mask_image(): | |
| target = Image(200, 200, Format.PRGB32) | |
| mask = Image(200, 200, Format.A8) | |
| with Context(mask) as mctx: | |
| mctx.fill_circle(100, 100, 50, 0xFF) | |
| with Context(target) as ctx: | |
| ctx.fill_all("black") | |
| ctx.mask_image(0, 0, mask, style="cyan") | |
| p = Path() | |
| p.add_rect(20, 20, 160, 160) | |
| with ctx.push_state(): | |
| ctx.clip_to_path(p) | |
| ctx.fill_all("red") | |
| ctx.restore_clipping() | |