orbimage 0.1.17

Orbital image features
Documentation
#![deny(warnings)]

extern crate orbclient;
extern crate orbimage;

use std::env;

use orbclient::{Color, EventOption, Renderer, Window, WindowFlag};
use orbimage::Image;

#[derive(Clone, Copy, Debug)]
enum BackgroundMode {
    /// Do not resize the image, just center it
    Center,
    /// Resize the image to the display size
    Fill,
    /// Resize the image - keeping its aspect ratio, and fit it to the display with blank space
    Scale,
    /// Resize the image - keeping its aspect ratio, and crop to remove all blank space
    Zoom,
}

impl BackgroundMode {
    fn from_str(string: &str) -> BackgroundMode {
        match string {
            "fill" => BackgroundMode::Fill,
            "scale" => BackgroundMode::Scale,
            "zoom" => BackgroundMode::Zoom,
            _ => BackgroundMode::Center
        }
    }
}

fn find_scale(image: &Image, mode: BackgroundMode, display_width: u32, display_height: u32) -> (u32, u32) {
    match mode {
        BackgroundMode::Center => {
            (image.width(), image.height())
        },
        BackgroundMode::Fill => {
            (display_width, display_height)
        },
        BackgroundMode::Scale => {
            let d_w = display_width as f64;
            let d_h = display_height as f64;
            let i_w = image.width() as f64;
            let i_h = image.height() as f64;

            let scale = if d_w / d_h > i_w / i_h {
                d_h / i_h
            } else {
                d_w / i_w
            };

            ((i_w * scale) as u32, (i_h * scale) as u32)
        },
        BackgroundMode::Zoom => {
            let d_w = display_width as f64;
            let d_h = display_height as f64;
            let i_w = image.width() as f64;
            let i_h = image.height() as f64;

            let scale = if d_w / d_h < i_w / i_h {
                d_h / i_h
            } else {
                d_w / i_w
            };

            ((i_w * scale) as u32, (i_h * scale) as u32)
        }
    }
}

fn main() {
    let mut args = env::args().skip(1);

    let path = match args.next() {
        Some(arg) => arg,
        None => "/ui/background.png".to_string(),
    };

    let mode = BackgroundMode::from_str(&args.next().unwrap_or(String::new()));

    match Image::from_path(&path) {
        Ok(image) => {
            let (display_width, display_height) = orbclient::get_display_size().expect("background: failed to get display size");

            let mut window = Window::new_flags(
                0, 0, display_width, display_height, &format!("{} - Background", path),
                &[WindowFlag::Back, WindowFlag::Borderless, WindowFlag::Unclosable]
            ).unwrap();

            let mut scaled_image = image.clone();
            let mut resize = Some((display_width, display_height));
            loop {
                if let Some((w, h)) = resize.take() {
                    let (width, height) = find_scale(&image, mode, w, h);

                    if width == scaled_image.width() && height == scaled_image.height() {
                        // Do not resize scaled image
                    } else if width == image.width() && height == image.height() {
                        scaled_image = image.clone();
                    } else {
                        scaled_image = image.resize(width, height, orbimage::ResizeType::Lanczos3).unwrap();
                    }

                    let (crop_x, crop_w) = if width > w  {
                        ((width - w)/2, w)
                    } else {
                        (0, width)
                    };

                    let (crop_y, crop_h) = if height > h {
                        ((height - h)/2, h)
                    } else {
                        (0, height)
                    };

                    window.set(Color::rgb(0, 0, 0));

                    let x = (w as i32 - crop_w as i32)/2;
                    let y = (h as i32 - crop_h as i32)/2;
                    scaled_image.roi(
                        crop_x, crop_y,
                        crop_w, crop_h,
                    ).draw(
                        &mut window,
                        x, y
                    );

                    window.sync();
                }

                for event in window.events() {
                    match event.to_option() {
                        EventOption::Resize(resize_event) => {
                            resize = Some((resize_event.width, resize_event.height));
                        },
                        EventOption::Screen(screen_event) => {
                            window.set_size(screen_event.width, screen_event.height);
                            resize = Some((screen_event.width, screen_event.height));
                        },
                        EventOption::Quit(_) => return,
                        _ => ()
                    }
                }
            }
        },
        Err(err) => {
            println!("background: error loading {}: {}", path, err);
        }
    }
}