Skip to content

GrigoryEvko/skia-graphics-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

skia-graphics-rs

A high-performance 2D graphics library for Rust, providing a complete HTML5 Canvas API implementation built on Google's Skia graphics engine.

This is a pure Rust port of the popular skia-canvas library, eliminating the need for Node.js bindings while maintaining full API compatibility.

Features

  • 🚀 High Performance: Hardware-accelerated rendering via Skia
  • 🎨 Complete Canvas API: Full HTML5 Canvas 2D context implementation
  • 🖼️ Advanced Graphics: Gradients, patterns, filters, and effects
  • 📝 Rich Typography: Advanced text rendering with OpenType features
  • 🔧 Path Operations: Boolean operations, interpolation, and effects
  • 🖥️ GPU Acceleration: Vulkan (Linux/Windows) and Metal (macOS) backends
  • 📦 Multiple Export Formats: PNG, JPEG, WebP, PDF, SVG
  • Battle-tested: 290+ tests ported from the original implementation

Installation

Add this to your Cargo.toml:

[dependencies]
skia-graphics-rs = "0.1.0"

Feature Flags

  • default: Includes async support
  • async: Async runtime support via Tokio
  • window: Desktop windowing support (experimental)
  • vulkan: Vulkan GPU backend
  • metal: Metal GPU backend (macOS)
  • freetype: FreeType font rendering with WOFF2 support
  • http: HTTP image loading support

Example with specific features:

[dependencies]
skia-graphics-rs = { version = "0.1.0", features = ["vulkan", "freetype"] }

Build Requirements

Currently requires a local skia-bindings patch. Add to your Cargo.toml:

[patch.crates-io]
skia-bindings = { path = "/tmp/rust-skia/skia-bindings" }

Quick Start

use skia_graphics_rs::{Canvas, Path2D};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a canvas
    let mut canvas = Canvas::new(800.0, 600.0)?;
    let ctx = canvas.get_context_2d();
    
    // Draw a red rectangle
    ctx.set_fill_style_color(255, 0, 0, 255);
    ctx.fill_rect(50.0, 50.0, 200.0, 100.0);
    
    // Draw a blue circle using Path2D
    let mut path = Path2D::new();
    path.arc(400.0, 300.0, 50.0, 0.0, std::f32::consts::PI * 2.0, false);
    ctx.set_fill_style_color(0, 0, 255, 255);
    ctx.fill_path(&path);
    
    // Add some text
    ctx.set_font_string("48px sans-serif");
    ctx.set_fill_style_color(0, 0, 0, 255);
    ctx.fill_text("Hello, Rust!", 250.0, 400.0);
    
    // Save to file
    canvas.save_as("output.png", 1.0)?;
    
    Ok(())
}

API Overview

Canvas Creation

// Create a canvas with dimensions
let canvas = Canvas::new(width, height)?;

// Get the 2D rendering context
let ctx = canvas.get_context_2d();

// Save to various formats
canvas.save_as("output.png", 1.0)?;  // PNG with quality
canvas.save_as("output.jpg", 0.9)?;  // JPEG with quality
canvas.save_as("output.pdf", 1.0)?;  // PDF
canvas.save_as("output.svg", 1.0)?;  // SVG

Drawing Operations

// Basic shapes
ctx.fill_rect(x, y, width, height);
ctx.stroke_rect(x, y, width, height);
ctx.clear_rect(x, y, width, height);

// Paths
ctx.begin_path();
ctx.move_to(x, y);
ctx.line_to(x, y);
ctx.arc(x, y, radius, start_angle, end_angle, anticlockwise);
ctx.bezier_curve_to(cp1x, cp1y, cp2x, cp2y, x, y);
ctx.quadratic_curve_to(cpx, cpy, x, y);
ctx.close_path();
ctx.fill();
ctx.stroke();

// Styles
ctx.set_fill_style_color(r, g, b, a);
ctx.set_stroke_style_color(r, g, b, a);
ctx.set_line_width(width);
ctx.set_line_cap("round"); // "butt", "round", "square"
ctx.set_line_join("miter"); // "miter", "round", "bevel"

Path2D Advanced Operations

let mut path1 = Path2D::new();
let mut path2 = Path2D::new();

// Boolean operations
let union = path1.union(&path2);
let intersection = path1.intersect(&path2);
let difference = path1.difference(&path2);
let xor = path1.xor(&path2);

// Path effects
let rounded = path.round(radius);
let trimmed = path.trim(start, end, false);
let simplified = path.simplify(FillType::Winding);

// Transformations
let transformed = path.transform(&matrix);
let offset = path.offset(dx, dy);

// Interpolation
let interpolated = path1.interpolate(&path2, 0.5);

Text Rendering

// Set font properties
ctx.set_font_string("bold 24px Arial");
ctx.set_text_align("center"); // "left", "right", "center", "start", "end"
ctx.set_text_baseline("middle"); // "top", "middle", "bottom", "alphabetic", etc.

// Draw text
ctx.fill_text("Hello", x, y);
ctx.stroke_text("World", x, y);

// Measure text
let metrics = ctx.measure_text("Sample text");
println!("Width: {}", metrics.width);

Gradients and Patterns

// Linear gradient
let gradient = ctx.create_linear_gradient(x0, y0, x1, y1);
gradient.add_color_stop(0.0, "red");
gradient.add_color_stop(1.0, "blue");
ctx.set_fill_style_gradient(&gradient);

// Radial gradient
let gradient = ctx.create_radial_gradient(x0, y0, r0, x1, y1, r1);
gradient.add_color_stop(0.0, "yellow");
gradient.add_color_stop(1.0, "green");

// Pattern from image
let pattern = ctx.create_pattern(&image, "repeat")?;
ctx.set_fill_style_pattern(&pattern);

Image Operations

// Load and draw images
let image = Image::from_file("image.png")?;
ctx.draw_image(&image, x, y);
ctx.draw_image_with_size(&image, x, y, width, height);

// Get/put image data
let image_data = ctx.get_image_data(x, y, width, height)?;
ctx.put_image_data(&image_data, x, y);

Transformations

// Transform the coordinate system
ctx.translate(x, y);
ctx.rotate(angle);
ctx.scale(x, y);
ctx.transform(a, b, c, d, e, f);
ctx.set_transform(a, b, c, d, e, f);
ctx.reset_transform();

// Save and restore state
ctx.save();
// ... drawing operations ...
ctx.restore();

Complete API Coverage

This library implements the complete HTML5 Canvas 2D API, including:

Drawing Methods

  • fillRect(), strokeRect(), clearRect()
  • fillText(), strokeText(), measureText()
  • beginPath(), closePath(), moveTo(), lineTo()
  • arc(), arcTo(), ellipse()
  • bezierCurveTo(), quadraticCurveTo()
  • rect(), roundRect()
  • fill(), stroke(), clip()
  • drawImage() (with multiple overloads)
  • getImageData(), putImageData(), createImageData()

Style Properties

  • fillStyle, strokeStyle
  • lineWidth, lineCap, lineJoin, miterLimit
  • lineDashOffset, setLineDash(), getLineDash()
  • font, textAlign, textBaseline, direction
  • globalAlpha, globalCompositeOperation
  • shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor
  • filter
  • imageSmoothingEnabled, imageSmoothingQuality

Path2D Methods

  • ✅ All standard path construction methods
  • addPath()
  • ✅ Boolean operations: union(), intersect(), difference(), xor(), complement()
  • ✅ Effects: round(), trim(), jitter(), simplify(), unwind()
  • ✅ Transformations: offset(), transform()
  • ✅ Analysis: bounds(), contains(), edges()
  • ✅ SVG: d property getter/setter

Examples

Drawing a Complex Shape

use skia_graphics_rs::{Canvas, Path2D};

let mut canvas = Canvas::new(500.0, 500.0)?;
let ctx = canvas.get_context_2d();

// Create a star path
let mut star = Path2D::new();
let points = 5;
let outer_radius = 100.0;
let inner_radius = 50.0;
let cx = 250.0;
let cy = 250.0;

for i in 0..(points * 2) {
    let radius = if i % 2 == 0 { outer_radius } else { inner_radius };
    let angle = (i as f32) * std::f32::consts::PI / (points as f32);
    let x = cx + angle.cos() * radius;
    let y = cy + angle.sin() * radius;
    
    if i == 0 {
        star.move_to(x, y);
    } else {
        star.line_to(x, y);
    }
}
star.close_path();

// Apply gradient fill
let gradient = ctx.create_radial_gradient(cx, cy, 0.0, cx, cy, outer_radius);
gradient.add_color_stop(0.0, "yellow");
gradient.add_color_stop(1.0, "orange");
ctx.set_fill_style_gradient(&gradient);
ctx.fill_path(&star);

// Add stroke
ctx.set_stroke_style_color(255, 0, 0, 255);
ctx.set_line_width(3.0);
ctx.stroke_path(&star);

Working with Filters

// Apply CSS filters
ctx.set_filter("blur(5px)");
ctx.draw_image(&image, 0.0, 0.0);

ctx.set_filter("contrast(200%) brightness(150%)");
ctx.draw_image(&image, 100.0, 0.0);

// Combine multiple filters
ctx.set_filter("sepia(100%) hue-rotate(90deg)");
ctx.draw_image(&image, 200.0, 0.0);

Testing

Run the test suite:

# Run all tests
cargo test

# Run specific test module
cargo test path2d

# Run with verbose output
cargo test -- --nocapture

The library includes 290+ tests ported from the original skia-canvas, ensuring complete API compatibility.

Migration from skia-canvas

This library maintains API compatibility with skia-canvas, making migration straightforward:

Key Differences:

  • Pure Rust implementation (no Node.js required)
  • Methods use snake_case instead of camelCase (Rust convention)
  • Color values use RGBA tuples instead of CSS strings in some low-level APIs
  • Async operations use Rust futures instead of JavaScript promises

Example Migration:

JavaScript (skia-canvas):

const {Canvas, Path2D} = require('@samizdatco/skia-canvas')

const canvas = new Canvas(400, 400)
const ctx = canvas.getContext('2d')

ctx.fillStyle = 'red'
ctx.fillRect(50, 50, 100, 100)

await canvas.saveAs('output.png')

Rust (skia-graphics-rs):

use skia_graphics_rs::{Canvas, Path2D};

let mut canvas = Canvas::new(400.0, 400.0)?;
let ctx = canvas.get_context_2d();

ctx.set_fill_style_color(255, 0, 0, 255);
ctx.fill_rect(50.0, 50.0, 100.0, 100.0);

canvas.save_as("output.png", 1.0)?;

Performance

The library leverages Skia's optimized rendering pipeline with:

  • Hardware acceleration via GPU backends (Vulkan/Metal)
  • Efficient path caching and reuse
  • Multi-threaded rendering operations
  • Optimized image decoding and caching

Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.

Development Setup

  1. Clone the repository:
git clone https://github.com/GrigoryEvko/skia-graphics-rs.git
cd skia-graphics-rs
  1. Build the project:
cargo build --release
  1. Run tests:
cargo test

License

MIT License - see LICENSE file for details.

Acknowledgments

Status

This is an active port from the original skia-canvas library. All core Canvas 2D API functionality has been implemented and tested. The library is suitable for production use in projects requiring high-performance 2D graphics rendering with Canvas API compatibility.

Roadmap

  • Complete GUI/windowing module
  • WebAssembly support
  • Additional export formats
  • Performance optimizations
  • Extended filter effects
  • Animation utilities

Support

For questions, issues, or contributions, please visit the GitHub repository.

About

Adapted from https://github.com/samizdatco/skia-canvas

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages