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}