Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

StrategyDescription
Eager (default)Load immediately when element is created
LazyLoad only when visible in viewport

Placeholder Types

PlaceholderDescription
NoneNo 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)
SkeletonShimmer 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)
                )
        )
}
}
#![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

  1. Set explicit dimensions - Images need width and height for layout.

  2. Use cover for photos - Fills container nicely without distortion.

  3. Use contain for diagrams - Ensures nothing is cropped.

  4. Tint icons - Use .tint() to match your color scheme.

  5. Use SVG for icons - Scales perfectly at any size.

  6. Optimize images - Use appropriate formats and compression for web.

  7. Use lazy loading for galleries - In scroll containers with many images, use .lazy() to reduce memory usage and improve initial load time.

  8. Use emoji images for large emoji - For emoji larger than ~24px, use emoji_sized() instead of text for crisp rendering.