Images & SVG
Blinc supports raster images and SVG graphics with flexible sizing and styling options.
Images
Basic Image
#![allow(unused)]
fn main() {
use blinc_layout::image::image;
image("path/to/photo.png")
.w(200.0)
.h(150.0)
}
Image from URL
#![allow(unused)]
fn main() {
image("https://example.com/image.jpg")
.w(300.0)
.h(200.0)
}
Object Fit
Control how the image fills its container:
#![allow(unused)]
fn main() {
image(src)
.w(200.0)
.h(200.0)
.cover() // Fill container, crop if needed (default)
image(src)
.contain() // Fit entirely, may letterbox
image(src)
.fill() // Stretch to fill exactly
image(src)
.scale_down() // Scale down only if larger
image(src)
.no_scale() // No scaling, original size
}
Object Position
Control alignment within the container:
#![allow(unused)]
fn main() {
image(src)
.cover()
.center() // Center (default)
image(src)
.cover()
.top_left()
image(src)
.cover()
.top_center()
image(src)
.cover()
.bottom_right()
// Custom position (0.0 to 1.0)
image(src)
.cover()
.position_xy(0.25, 0.75)
}
Image Filters
#![allow(unused)]
fn main() {
image(src)
.w(200.0)
.h(200.0)
.grayscale(0.5) // 0.0 = color, 1.0 = grayscale
.sepia(0.3) // Sepia tone
.brightness(1.2) // > 1.0 brighter, < 1.0 darker
.contrast(1.1) // > 1.0 more contrast
.saturate(0.8) // < 1.0 less saturated
.hue_rotate(45.0) // Rotate hue (degrees)
.invert(0.2) // Color inversion
.blur(2.0) // Blur radius
}
Lazy Loading
For content-heavy applications with many images (galleries, feeds, chat apps), lazy loading defers image loading until the image is visible in the viewport. This reduces initial memory usage and load time.
#![allow(unused)]
fn main() {
use blinc_layout::prelude::*;
use std::time::Duration;
// Basic lazy loading
img("large-photo.jpg")
.lazy()
.w(300.0)
.h(200.0)
// With placeholder color
img("photo.jpg")
.lazy()
.placeholder_color(Color::rgba(0.2, 0.2, 0.2, 1.0))
.w(300.0)
.h(200.0)
// With gradient placeholder using Brush
img("photo.jpg")
.lazy()
.placeholder_brush(Brush::Gradient(Gradient::linear(
Point::new(0.0, 0.0),
Point::new(1.0, 1.0),
Color::rgba(0.4, 0.6, 1.0, 1.0),
Color::rgba(0.6, 0.4, 1.0, 1.0),
)))
.w(300.0)
.h(200.0)
// With thumbnail placeholder
img("large-photo.jpg")
.lazy()
.placeholder_image("thumbnail.jpg")
.fade_in(Duration::from_millis(300))
.w(300.0)
.h(200.0)
// Skeleton loading animation
img("photo.jpg")
.lazy()
.skeleton()
.fade_in(Duration::from_millis(250))
.w(300.0)
.h(200.0)
// Disable fade animation
img("photo.jpg")
.lazy()
.no_fade()
.w(300.0)
.h(200.0)
}
Loading Strategies
| Strategy | Description |
|---|---|
Eager (default) | Load immediately when element is created |
Lazy | Load only when visible in viewport |
Placeholder Types
| Placeholder | Description |
|---|---|
None | No placeholder (blank until loaded) |
Color(color) | Solid color background |
Brush(brush) | Any brush (gradient, glass effect, etc.) |
Image(url) | Another image (e.g., low-res thumbnail, blur hash) |
Skeleton | Shimmer loading animation |
Emoji Images
Render emoji as images at arbitrary sizes using the system emoji font. Emoji images are automatically lazy-loaded for memory efficiency.
#![allow(unused)]
fn main() {
use blinc_layout::image::{emoji, emoji_sized};
// Default size (64px)
emoji("😀")
// Custom size
emoji_sized("🚀", 128.0)
// In a layout
div()
.flex_row()
.gap(8.0)
.child(emoji_sized("👍", 32.0))
.child(emoji_sized("🎉", 32.0))
.child(emoji_sized("✨", 32.0))
}
Emoji images use the system color emoji font (Apple Color Emoji on macOS, Segoe UI Emoji on Windows, Noto Color Emoji on Linux).
SVG
Basic SVG
#![allow(unused)]
fn main() {
use blinc_layout::svg::svg;
svg("icons/menu.svg")
.w(24.0)
.h(24.0)
}
SVG with Tint
Apply a color tint to monochrome SVGs:
#![allow(unused)]
fn main() {
svg("icons/settings.svg")
.w(24.0)
.h(24.0)
.tint(Color::WHITE)
svg("icons/error.svg")
.w(20.0)
.h(20.0)
.tint(Color::rgba(0.9, 0.3, 0.3, 1.0))
}
SVG Sizing
#![allow(unused)]
fn main() {
// Fixed size
svg(src).w(32.0).h(32.0)
// Square shorthand
svg(src).square(24.0)
// Aspect ratio preserved
svg(src).w(48.0).h_auto()
}
Common Patterns
Avatar Image
#![allow(unused)]
fn main() {
fn avatar(url: &str, size: f32) -> impl ElementBuilder {
image(url)
.w(size)
.h(size)
.cover()
.rounded_full() // Circular
}
}
Icon Button
#![allow(unused)]
fn main() {
use blinc_layout::stateful::stateful;
fn icon_button(ctx: &WindowedContext, icon_path: &str) -> impl ElementBuilder {
// Use use_state_for with icon_path as key for reusable component
let handle = ctx.use_state_for(icon_path, ButtonState::Idle);
stateful(handle)
.w(40.0)
.h(40.0)
.rounded(8.0)
.flex_center()
.on_state(|state, div| {
let bg = match state {
ButtonState::Idle => Color::TRANSPARENT,
ButtonState::Hovered => Color::rgba(0.2, 0.2, 0.25, 1.0),
ButtonState::Pressed => Color::rgba(0.15, 0.15, 0.2, 1.0),
_ => Color::TRANSPARENT,
};
div.set_bg(bg);
})
.child(
svg(icon_path)
.w(20.0)
.h(20.0)
.tint(Color::WHITE)
)
}
}
Image Card
#![allow(unused)]
fn main() {
fn image_card(image_url: &str, title: &str) -> impl ElementBuilder {
div()
.w(300.0)
.rounded(12.0)
.overflow_clip()
.bg(Color::rgba(0.15, 0.15, 0.2, 1.0))
.child(
image(image_url)
.w_full()
.h(180.0)
.cover()
)
.child(
div()
.p(16.0)
.child(
text(title)
.size(18.0)
.weight(FontWeight::SemiBold)
.color(Color::WHITE)
)
)
}
}
Gallery Grid
#![allow(unused)]
fn main() {
fn gallery(images: &[&str]) -> impl ElementBuilder {
div()
.flex_row()
.flex_wrap()
.gap(8.0)
.child(
images.iter().map(|url| {
image(*url)
.w(150.0)
.h(150.0)
.cover()
.rounded(8.0)
})
)
}
}
Placeholder with Fallback
#![allow(unused)]
fn main() {
fn image_with_placeholder(url: Option<&str>) -> impl ElementBuilder {
match url {
Some(src) => image(src)
.w(200.0)
.h(200.0)
.cover()
.rounded(8.0),
None => div()
.w(200.0)
.h(200.0)
.rounded(8.0)
.bg(Color::rgba(0.2, 0.2, 0.25, 1.0))
.flex_center()
.child(
svg("icons/image-placeholder.svg")
.w(48.0)
.h(48.0)
.tint(Color::rgba(0.4, 0.4, 0.5, 1.0))
),
}
}
}
Supported Formats
Images
- PNG
- JPEG
- WebP
- GIF (first frame)
- BMP
- ICO
SVG
- Standard SVG 1.1
- Path elements
- Basic shapes (rect, circle, ellipse, line, polyline, polygon)
- Transforms
- Fill and stroke
Best Practices
-
Set explicit dimensions - Images need width and height for layout.
-
Use
coverfor photos - Fills container nicely without distortion. -
Use
containfor diagrams - Ensures nothing is cropped. -
Tint icons - Use
.tint()to match your color scheme. -
Use SVG for icons - Scales perfectly at any size.
-
Optimize images - Use appropriate formats and compression for web.
-
Use lazy loading for galleries - In scroll containers with many images, use
.lazy()to reduce memory usage and improve initial load time. -
Use emoji images for large emoji - For emoji larger than ~24px, use
emoji_sized()instead of text for crisp rendering.