Back to Blog

Build Image Filters with egui Sliders | Rust GUI Tutorial #14

Sandy LaneSandy Lane

Video: Build Image Filters with egui Sliders | Rust GUI Tutorial #14 by Taught by Celeste AI - AI Coding Coach

Watch full page →

Build Image Filters with egui Sliders | Rust GUI Tutorial #14

Learn how to create an interactive image filter app in Rust using egui sliders to adjust brightness, contrast, saturation, and blur in real-time. This tutorial demonstrates binding slider values to filter parameters and rendering a live color preview to visualize changes instantly.

Code

use eframe::{egui, epi};

#[derive(Default)]
struct MyApp {
  brightness: f32,  // brightness adjustment: -100% to +100%
  contrast: f32,    // contrast adjustment: -100% to +100%
  saturation: f32,  // saturation adjustment: -100% to +100%
  blur: f32,        // blur radius in pixels: 0 to 10
}

impl MyApp {
  // Calculate a preview color based on filter settings (simplified)
  fn preview_color(&self) -> egui::Color32 {
    // Start with a mid gray base color
    let base = 128.0;

    // Apply brightness: shift base color by brightness percentage
    let bright = (base + base * self.brightness / 100.0).clamp(0.0, 255.0);

    // Apply contrast: scale difference from 128 by contrast factor
    let contrast_factor = (self.contrast / 100.0) + 1.0;
    let contrasted = ((bright - 128.0) * contrast_factor + 128.0).clamp(0.0, 255.0);

    // Apply saturation: here simplified as a grayscale intensity adjustment
    let saturation_factor = (self.saturation / 100.0) + 1.0;
    let saturated = (contrasted * saturation_factor).clamp(0.0, 255.0);

    egui::Color32::from_gray(saturated as u8)
  }
}

impl epi::App for MyApp {
  fn name(&self) -> &str {
    "Image Filters with egui Sliders"
  }

  fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
    egui::CentralPanel::default().show(ctx, |ui| {
      ui.heading("Adjust Image Filters");

      // Brightness slider with "%" suffix
      ui.add(
        egui::Slider::new(&mut self.brightness, -100.0..=100.0)
          .text("Brightness")
          .suffix("%"),
      );

      // Contrast slider with "%" suffix
      ui.add(
        egui::Slider::new(&mut self.contrast, -100.0..=100.0)
          .text("Contrast")
          .suffix("%"),
      );

      // Saturation slider with "%" suffix
      ui.add(
        egui::Slider::new(&mut self.saturation, -100.0..=100.0)
          .text("Saturation")
          .suffix("%"),
      );

      // Blur slider with "px" suffix
      ui.add(
        egui::Slider::new(&mut self.blur, 0.0..=10.0)
          .text("Blur")
          .suffix("px"),
      );

      // Reset button to default values
      if ui.button("Reset All").clicked() {
        *self = MyApp::default();
      }

      ui.separator();

      // Draw preview rectangle showing the current filter color
      let preview_color = self.preview_color();
      let (rect, _response) = ui.allocate_exact_size(egui::vec2(100.0, 100.0), egui::Sense::hover());
      ui.painter().rect_filled(rect, 0.0, preview_color);

      ui.label(format!(
        "Preview Color - Brightness: {:.0}%, Contrast: {:.0}%, Saturation: {:.0}%, Blur: {:.1}px",
        self.brightness, self.contrast, self.saturation, self.blur
      ));
    });
  }
}

fn main() {
  let app = MyApp::default();
  let native_options = eframe::NativeOptions::default();
  eframe::run_native(Box::new(app), native_options);
}

Key Points

  • Use egui::Slider::new to bind mutable f32 values to sliders with defined ranges.
  • Add units like "%" or "px" to sliders using the .suffix() method for clarity.
  • Implement simple image filter math for brightness, contrast, and saturation to update preview colors dynamically.
  • Draw a live color preview rectangle using allocate_exact_size and rect_filled for immediate visual feedback.
  • Provide a "Reset All" button to restore default filter values by resetting the app state.