Skip to main content

skia_rs/
lib.rs

1//! # skia-rs
2//!
3//! A pure Rust implementation of Google's Skia 2D graphics library.
4//!
5//! This crate provides a comprehensive 2D graphics API for rendering shapes,
6//! images, text, and more. It is designed to be a drop-in replacement for
7//! the original Skia library while providing a safe, idiomatic Rust API.
8//!
9//! ## Quick Start
10//!
11//! ```rust,no_run
12//! use skia_rs::prelude::*;
13//!
14//! // Create a surface to draw on
15//! let mut surface = Surface::new_raster_n32_premul(800, 600).unwrap();
16//! let mut canvas = surface.canvas();
17//!
18//! // Create a paint for styling
19//! let mut paint = Paint::default();
20//! paint.set_color(Color::RED.into());
21//! paint.set_anti_alias(true);
22//!
23//! // Draw a circle
24//! canvas.draw_circle(Point::new(400.0, 300.0), 100.0, &paint);
25//! ```
26//!
27//! ## Feature Flags
28//!
29//! This crate uses feature flags to control which components are included:
30//!
31//! - **default** = `["std", "codec", "svg"]` - Standard features for most use cases
32//! - **std** - Standard library support (disable for `no_std` environments)
33//! - **serde** - Serialization support via serde
34//!
35//! ### Image Codecs
36//! - **codec** - Base image codec support
37//! - **codec-png** - PNG encoding/decoding
38//! - **codec-jpeg** - JPEG encoding/decoding
39//! - **codec-webp** - WebP encoding/decoding
40//! - **codec-gif** - GIF decoding
41//! - **codec-avif** - AVIF encoding/decoding
42//! - **codec-raw** - RAW image processing
43//! - **codec-all** - All image codecs
44//!
45//! ### Specialized Modules
46//! - **svg** - SVG parsing and rendering
47//! - **pdf** - PDF document generation
48//! - **text** - Advanced text rendering and shaping
49//! - **skottie** - Lottie animation support
50//!
51//! ### GPU Backends
52//! - **gpu** - Base GPU support
53//! - **vulkan** - Vulkan backend
54//! - **opengl** - OpenGL backend
55//! - **metal** - Metal backend (macOS/iOS only)
56//! - **wgpu-backend** / **webgpu** - wgpu backend (cross-platform)
57//!
58//! ### FFI
59//! - **ffi** - C FFI bindings for interoperability
60//!
61//! ### Full Features
62//! - **full** - Enables all features except platform-specific GPU backends
63//!
64//! ## Module Organization
65//!
66//! - [`core`] - Fundamental types: `Scalar`, `Point`, `Rect`, `Color`, `Matrix`
67//! - [`path`] - Path geometry: `Path`, `PathBuilder`, `PathOps`, `PathEffect`
68//! - [`paint`] - Styling: `Paint`, `Shader`, `BlendMode`, `Filter`
69//! - [`canvas`] - Drawing: `Canvas`, `Surface`, `Picture`
70//! - [`safe`] - High-level ergonomic API (recommended for most users)
71//!
72//! Optional modules (enabled via features):
73//! - [`text`] - Typography: font loading, text shaping, layout
74//! - [`codec`] - Image I/O: PNG, JPEG, GIF, WebP, AVIF
75//! - [`svg`] - SVG parsing and rendering
76//! - [`pdf`] - PDF document generation
77//! - [`gpu`] - GPU rendering backends
78//! - [`skottie`] - Lottie/Skottie animation
79//! - [`ffi`] - C FFI bindings
80
81#![cfg_attr(not(feature = "std"), no_std)]
82#![cfg_attr(docsrs, feature(doc_cfg))]
83#![warn(missing_docs)]
84#![warn(clippy::all)]
85#![allow(clippy::module_inception)]
86
87// Re-export core crates
88pub use skia_rs_core as core;
89pub use skia_rs_path as path;
90pub use skia_rs_paint as paint;
91pub use skia_rs_canvas as canvas;
92pub use skia_rs_safe as safe;
93
94// Optional crate re-exports
95#[cfg(feature = "text")]
96#[cfg_attr(docsrs, doc(cfg(feature = "text")))]
97pub use skia_rs_text as text;
98
99#[cfg(feature = "codec")]
100#[cfg_attr(docsrs, doc(cfg(feature = "codec")))]
101pub use skia_rs_codec as codec;
102
103#[cfg(feature = "svg")]
104#[cfg_attr(docsrs, doc(cfg(feature = "svg")))]
105pub use skia_rs_svg as svg;
106
107#[cfg(feature = "pdf")]
108#[cfg_attr(docsrs, doc(cfg(feature = "pdf")))]
109pub use skia_rs_pdf as pdf;
110
111#[cfg(feature = "gpu")]
112#[cfg_attr(docsrs, doc(cfg(feature = "gpu")))]
113pub use skia_rs_gpu as gpu;
114
115#[cfg(feature = "skottie")]
116#[cfg_attr(docsrs, doc(cfg(feature = "skottie")))]
117pub use skia_rs_skottie as skottie;
118
119#[cfg(feature = "ffi")]
120#[cfg_attr(docsrs, doc(cfg(feature = "ffi")))]
121pub use skia_rs_ffi as ffi;
122
123/// Prelude module for convenient imports.
124///
125/// Import all commonly used types with:
126/// ```rust
127/// use skia_rs::prelude::*;
128/// ```
129pub mod prelude {
130    // Core types
131    pub use skia_rs_core::{
132        AlphaType, Color, Color4f, ColorSpace, ColorType, IPoint, IRect, ISize, ImageInfo, Matrix,
133        Point, Rect, Scalar, Size,
134    };
135
136    // Path types
137    pub use skia_rs_path::{FillType, Path, PathBuilder, PathDirection};
138
139    // Paint types
140    pub use skia_rs_paint::{BlendMode, Paint, Style};
141
142    // Canvas types
143    pub use skia_rs_canvas::{Canvas, ClipOp, SaveLayerRec, Surface};
144
145    // Safe wrapper types (high-level API)
146    pub use skia_rs_safe::prelude::*;
147
148    // Optional module prelude re-exports
149    #[cfg(feature = "text")]
150    #[cfg_attr(docsrs, doc(cfg(feature = "text")))]
151    pub use skia_rs_text::{Font, FontStyle, TextBlob, Typeface};
152
153    #[cfg(feature = "codec")]
154    #[cfg_attr(docsrs, doc(cfg(feature = "codec")))]
155    pub use skia_rs_codec::{ImageDecoder, ImageEncoder, ImageFormat};
156
157    #[cfg(feature = "svg")]
158    #[cfg_attr(docsrs, doc(cfg(feature = "svg")))]
159    pub use skia_rs_svg::SvgDom;
160
161    #[cfg(feature = "pdf")]
162    #[cfg_attr(docsrs, doc(cfg(feature = "pdf")))]
163    pub use skia_rs_pdf::PdfDocument;
164
165    #[cfg(feature = "gpu")]
166    #[cfg_attr(docsrs, doc(cfg(feature = "gpu")))]
167    pub use skia_rs_gpu::GpuContext;
168
169    #[cfg(feature = "skottie")]
170    #[cfg_attr(docsrs, doc(cfg(feature = "skottie")))]
171    pub use skia_rs_skottie::Animation;
172}
173
174/// Version information for the skia-rs library.
175pub mod version {
176    /// The major version number.
177    pub const MAJOR: u32 = parse_component(env!("CARGO_PKG_VERSION_MAJOR"));
178    /// The minor version number.
179    pub const MINOR: u32 = parse_component(env!("CARGO_PKG_VERSION_MINOR"));
180    /// The patch version number.
181    pub const PATCH: u32 = parse_component(env!("CARGO_PKG_VERSION_PATCH"));
182
183    /// The full version string.
184    pub const VERSION: &str = env!("CARGO_PKG_VERSION");
185
186    /// Returns the version as a tuple.
187    #[inline]
188    pub const fn as_tuple() -> (u32, u32, u32) {
189        (MAJOR, MINOR, PATCH)
190    }
191
192    /// Parse a decimal version component at compile time.
193    ///
194    /// Previously each component was a hand-maintained `const` literal; if
195    /// one fell behind the workspace version the constants desynced from
196    /// `CARGO_PKG_VERSION` and the unit test comparing them against the
197    /// string version failed. Deriving each component from its own cargo
198    /// env var makes the drift impossible.
199    const fn parse_component(s: &str) -> u32 {
200        let bytes = s.as_bytes();
201        let mut i = 0;
202        let mut n: u32 = 0;
203        while i < bytes.len() {
204            let b = bytes[i];
205            assert!(b >= b'0' && b <= b'9', "version component must be decimal");
206            n = n * 10 + (b - b'0') as u32;
207            i += 1;
208        }
209        n
210    }
211}
212
213#[cfg(test)]
214mod tests {
215    use super::*;
216
217    #[test]
218    fn test_version() {
219        assert_eq!(version::VERSION, env!("CARGO_PKG_VERSION"));
220        let parts: Vec<u32> = env!("CARGO_PKG_VERSION")
221            .split('.')
222            .map(|p| p.parse().unwrap())
223            .collect();
224        assert_eq!(
225            version::as_tuple(),
226            (parts[0], parts[1], parts[2])
227        );
228    }
229
230    #[test]
231    fn test_core_re_export() {
232        let point = core::Point::new(10.0, 20.0);
233        assert_eq!(point.x, 10.0);
234        assert_eq!(point.y, 20.0);
235    }
236
237    #[test]
238    fn test_prelude_imports() {
239        use crate::prelude::*;
240
241        let color = Color::RED;
242        assert_eq!(color.red(), 255);
243
244        let rect = Rect::from_xywh(0.0, 0.0, 100.0, 100.0);
245        assert_eq!(rect.width(), 100.0);
246    }
247}