diff --git a/src/main.rs b/src/main.rs index 8ac0505..14febde 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,11 @@ use std::{env, ffi::OsStr, fs}; use iced::{ - Color, Element, Length, Renderer, Subscription, Task, Theme, color, event, + Alignment, Color, Element, Length, Renderer, Subscription, Task, Theme, color, event, keyboard::{self, Key, key}, theme, widget, window, }; -use image::{ - EncodableLayout, ImageReader, Pixel, Rgba, RgbaImage, codecs::webp::WebPEncoder, imageops, -}; +use image::{EncodableLayout, ImageReader, RgbaImage, codecs::webp::WebPEncoder, imageops}; use rfd::FileDialog; #[derive(Clone, Debug)] @@ -19,32 +17,22 @@ enum Message { #[derive(Clone, Debug)] struct State { - image: RgbaImage, + image: Option, image_display: Option, } impl State { fn new() -> (Self, Task) { - let image = if let Some(path) = env::args().nth(1) { - ImageReader::open(path) - .unwrap() - .decode() - .unwrap() - .into_rgba8() - } else { - let mut image = RgbaImage::new(100, 100); - - imageops::horizontal_gradient( - &mut image, - Rgba::from_slice(&[0, 0, 0, 0]), - Rgba::from_slice(&[255, 255, 255, 255]), - ); - - image - }; - let state = State { image_display: None, - image, + image: env::args().nth(1).and_then(|path| { + Some( + ImageReader::open(path) + .unwrap() + .decode() + .unwrap() + .into_rgba8(), + ) + }), }; let allocate_image = state.allocate_image(); @@ -57,7 +45,12 @@ impl State { .height(Length::Fill) .into() } else { - widget::space().into() + widget::container(widget::text(include_str!("usage.txt"))) + .height(Length::Fill) + .width(Length::Fill) + .align_x(Alignment::Center) + .align_y(Alignment::Center) + .into() } } fn update(&mut self, message: Message) -> Task { @@ -80,17 +73,6 @@ impl State { } } - Key::Character("q") => return window::latest().and_then(window::close), - - Key::Character("r") => { - self.image = imageops::rotate90(&self.image); - return self.allocate_image(); - } - Key::Character("i") => { - imageops::invert(&mut self.image); - return self.allocate_image(); - } - Key::Character("o") => { let Some(path) = FileDialog::new() .add_filter( @@ -106,15 +88,40 @@ impl State { return Task::none(); }; - self.image = ImageReader::open(path) - .unwrap() - .decode() - .unwrap() - .into_rgba8(); + self.image = Some( + ImageReader::open(path) + .unwrap() + .decode() + .unwrap() + .into_rgba8(), + ); return self.allocate_image(); } + + Key::Character("r") => { + let Some(image) = self.image.as_ref() else { + eprintln!("no image to rotate"); + return Task::none(); + }; + self.image = Some(imageops::rotate90(image)); + return self.allocate_image(); + } + Key::Character("i") => { + let Some(image) = self.image.as_mut() else { + eprintln!("no image to invert"); + return Task::none(); + }; + imageops::invert(image); + return self.allocate_image(); + } + Key::Character("s") => { + let Some(image) = self.image.as_ref() else { + eprintln!("no image to save"); + return Task::none(); + }; + let Some(path) = FileDialog::new().save_file() else { eprintln!("no path to save provided"); return Task::none(); @@ -134,15 +141,17 @@ impl State { }; let result = if let Some(encoder) = maybe_encoder { - self.image.write_with_encoder(encoder) + image.write_with_encoder(encoder) } else { - self.image.save(path) + image.save(path) }; #[allow(unused_must_use)] result.inspect_err(|e| eprintln!("failed to save image: {e}")); } + Key::Character("q") => return window::latest().and_then(window::close), + // ignore unused keys _ => {} }, @@ -155,10 +164,15 @@ impl State { } fn allocate_image(&self) -> Task { + let Some(image) = self.image.as_ref() else { + eprintln!("no image to allocate"); + return Task::none(); + }; + widget::image::allocate(widget::image::Handle::from_rgba( - self.image.width(), - self.image.height(), - unsafe { std::mem::transmute::<_, &'static [u8]>(self.image.as_bytes()) }, + image.width(), + image.height(), + unsafe { std::mem::transmute::<_, &'static [u8]>(image.as_bytes()) }, )) .map(Message::ImageDisplayReady) } diff --git a/src/usage.txt b/src/usage.txt new file mode 100644 index 0000000..94cf3cf --- /dev/null +++ b/src/usage.txt @@ -0,0 +1,5 @@ +"o" to open a new image +"r" to rotate +"i" to invert colors +"s" to save the image +"q" to quit