tiny-skia

repository·main·Indexed 23 days ago

https://github.com/linebender/tiny-skia

A minimal, CPU-only 2D rendering library for Rust that implements a subset of Skia's algorithms. It provides high-quality rendering with a small footprint, supporting operations such as filling and stroking shapes with colors, gradients, or patterns, clipping, image blending, and PNG load/save. The library includes tiny-skia-path for memory-efficient Bezier path management, construction via PathBuilder, and path stroking/dashing.

Tokens
11.8K
Snippets
15
Records
78
Agent score
81%

What's inside tiny-skia

  1. Overview of tiny-skia-path

    main

    tiny-skia-path is a Bezier path implementation designed for use with tiny-skia. It provides tools for managing and manipulating paths, specifically focusing on memory efficiency and compatibility with Skia's precision model.

    Key features include:

    • Bezier path container: A memory-efficient way to store path data.
    • Path builder: Tools to construct complex paths.
    • Path stroker: Functionality to create outlines (strokes) from paths.
    • Path dasher: Functionality to create dashed lines from paths.
    • Geometry types: Basic geometric primitives (note: these are planned to move to an external crate in the future).

    Technical Note: All types use single-precision floats (f32) to maintain parity with Skia.

  2. Overview of tiny-skia

    main

    tiny-skia is a minimal, CPU-only 2D rendering library for Rust. It is a subset of Skia ported to Rust, focusing on rendering quality, speed, and small binary size. It is designed to be easy to build and distribute compared to full Skia or other heavy 2D libraries like Cairo or Qt.

    Supported Operations

    • Filling and stroking shapes with solid colors, gradients, or patterns.
    • Stroke dashing.
    • Clipping.
    • Image blending.
    • PNG load/save.

    Limitations and Out of Scope

    • No Text Rendering: This is a major missing feature.
    • No GPU Rendering: It is strictly CPU-based.
    • No PDF Generation.
    • No Advanced Path Operations: Does not support advanced Bézier path operations, conic path segments, or path effects (except dashing).
    • No Resource Caching or ICC profiles.
    • No Non-RGBA8888 images or non-PNG formats.
    • No Global Alpha: Unlike Skia, only Pattern can have opacity. For other operations, you must adjust color opacity manually.
  3. Run tiny-skia benchmarks

    main

    Benchmarks require the nightly Rust toolchain. To run the default benchmarks (which only test tiny-skia), install the nightly toolchain and use rustup run nightly cargo bench.

    To compare tiny-skia against other libraries like skia-rs, raqote, or cairo-rs, you must enable them via the --features flag. Note that enabling these requires additional setup, such as installing cairo or building Skia from source.

  4. Build Skia from source for benchmarking

    main

    To use skia-rs in benchmarks, you must build Skia from source.

    Prerequisites:

    • git, clang, ninja, and Python.
    • Windows: Use clang-cl and clang-cl++ for cc and cxx.
    • macOS (M1): Remove "-march=haswell" from extra_cflags_cc.

    Build Steps:

    1. Clone the Skia repository and checkout the chrome/m90 branch.
    2. Run tools/git-sync-deps to download dependencies (~3 GiB).
    3. Generate the build configuration using bin/gn with specific arguments to minimize the build size and focus on rasterization.
    4. Build using ninja.
    git clone https://skia.googlesource.com/skia.git
    cd skia
    git fetch --all
    git checkout -b m90 origin/chrome/m90
    python3 tools/git-sync-deps
    bin/gn gen out/Shared --args='
        is_official_build=false
        is_component_build=true
        is_debug=false
        cc="clang"
        cxx="clang++"
        extra_cflags_cc=["-march=haswell", "-DSK_FORCE_RASTER_PIPELINE_BLITTER"]
        werror=false
        paragraph_gms_enabled=false
        paragraph_tests_enabled=false
        skia_enable_android_utils=false
        skia_enable_discrete_gpu=false
        skia_enable_gpu=false
        skia_enable_nvpr=false
        skia_enable_pdf=false
        skia_enable_skottie=false
        skia_enable_skrive=false
        skia_enable_skshaper=false
        skia_enable_tools=false
        skia_use_expat=false
        skia_use_gl=false
        skia_use_harfbuzz=false
        skia_use_icu=false
        skia_use_libgifcodec=false
        skia_use_libheif=false
        skia_use_libjpeg_turbo_decode=false
        skia_use_libjpeg_turbo_encode=false
        skia_use_libwebp_decode=false
        skia_use_libwebp_encode=false
        skia_use_lua=false
        skia_use_piex=false'
    ninja -C out/Shared
  5. Configure environment for skia-rs benchmarks

    main

    When running benchmarks with the skia-rs feature enabled, you must provide the paths to your Skia installation using the following environment variables:

    • SKIA_DIR: The root directory of your Skia build.
    • SKIA_LIB_DIR: The directory containing the Skia shared libraries (e.g., out/Shared).
    • LD_LIBRARY_PATH: Must include the path to the Skia shared libraries so the linker can find them at runtime.
    export SKIA_DIR="/path/to/skia"
    export SKIA_LIB_DIR="/path/to/skia/out/Shared"
    export LD_LIBRARY_PATH="/path/to/skia/out/Shared"
  6. Optimize tiny-skia performance with RUSTFLAGS

    main

    By default, tiny-skia provides decent performance on x86 targets. However, to achieve better performance by enabling AVX instructions on x86-64, you should compile your application with the RUSTFLAGS environment variable set to -Ctarget-cpu=haswell.

    On ARM AArch64, NEON support is included by default and does not require additional flags.

    RUSTFLAGS="-Ctarget-cpu=haswell"
  7. What is a Mask and how does it work?

    main

    A Mask is an 8-bit alpha mask used for clipping and masking operations during drawing. In a mask, black (0) pixels block rendering, while white (255) pixels allow it. Intermediate values are used for gradual masking and anti-aliasing.

    Unlike Skia, tiny-skia uses a simple 8-bit alpha mask for efficiency and implementation simplicity.

  8. Create and manipulate 2D affine transformations with `Transform`

    main

    The Transform struct represents an affine transformation matrix used for 2D coordinate transformations. It uses column-major-column-vector matrix notation.

    Note on Validity: Unlike many mathematical libraries, Transform does not guarantee validity. It follows a Skia quirk where non-finite values or zero-scale transforms (like Transform(0, 0, 0, 0, 0, 0)) are technically allowed and do not trigger errors.

  9. Understand the tiny-skia drawing model

    main

    Unlike higher-level drawing APIs (like HTML Canvas or Skia), tiny-skia provides low-level drawing primitives. Users are responsible for manually managing:

    • World Transforms: Applying transformations to the coordinate system.
    • Clipping Masks: Defining the visible area for drawing.
    • Styles: Managing how shapes and lines are rendered.

    For practical implementation patterns, refer to the examples/ directory in the repository.

  10. Use the Shader enum for advanced fills

    main

    A Shader specifies the source color(s) for what is being drawn. If a Paint has a shader, the shader's colors are used instead of the paint's color, but they are modulated by the paint's alpha. This allows you to change the transparency of a shape without modifying the underlying shader.

    Supported shader types:

    • SolidColor(Color)
    • LinearGradient(LinearGradient)
    • RadialGradient(RadialGradient)
    • SweepGradient(SweepGradient)
    • Pattern(Pattern<'a>)
    #[derive(Clone, PartialEq, Debug)]
    pub enum Shader<'a> {
        /// A solid color shader.
        SolidColor(Color),
        /// A linear gradient shader.
        LinearGradient(LinearGradient),
        /// A radial gradient shader.
        RadialGradient(RadialGradient),
        /// A sweep gradient shader.
        SweepGradient(SweepGradient),
        /// A pattern shader.
        Pattern(Pattern<'a>),
    }
  11. Manage pixel buffers with Pixmap

    main

    The Pixmap struct is a container that owns premultiplied RGBA pixels. It is used as a primary drawing surface in tiny-skia. Pixmap data is not aligned, meaning the width is equal to the stride.

    Key Characteristics

    • Color Format: Premultiplied RGBA.
    • Byte Order: RGBA.
    • Memory Layout: Linear, non-aligned (width == stride).
    • Constraints: Width is limited by i32::MAX / 4.