feat: image copy and paste
This commit is contained in:
parent
1f909904c2
commit
cb5e1d837a
5 changed files with 155 additions and 2 deletions
51
src/main.rs
51
src/main.rs
|
|
@ -6,6 +6,7 @@ use std::{
|
|||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use arboard::Clipboard;
|
||||
use iced::{
|
||||
Alignment, Color, Element, Length, Renderer, Subscription, Task, Theme, event,
|
||||
keyboard::{self, Key, key},
|
||||
|
|
@ -26,7 +27,7 @@ enum Message {
|
|||
Event(iced::Event),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Default)]
|
||||
struct State {
|
||||
image: Option<RgbaImage>,
|
||||
image_display: Option<widget::image::Allocation>,
|
||||
|
|
@ -35,6 +36,8 @@ struct State {
|
|||
error: Option<String>,
|
||||
info: Option<String>,
|
||||
infobar_shown: bool,
|
||||
|
||||
clipboard: Option<Clipboard>,
|
||||
}
|
||||
impl State {
|
||||
fn new() -> (Self, Task<Message>) {
|
||||
|
|
@ -166,6 +169,52 @@ impl State {
|
|||
|
||||
Key::Character("q") => return window::latest().and_then(window::close),
|
||||
|
||||
Key::Character("y") | Key::Character("c") => {
|
||||
if let Some(image) = self.image.as_ref() {
|
||||
match match self.clipboard.take() {
|
||||
Some(c) => Ok(c),
|
||||
None => Clipboard::new(),
|
||||
} {
|
||||
Ok(mut clipboard) => {
|
||||
self.error = clipboard
|
||||
.set_image(utils::arboard_from_rgbaimage(image))
|
||||
.map_err(|e| e.to_string())
|
||||
.err();
|
||||
self.clipboard = Some(clipboard);
|
||||
}
|
||||
Err(e) => self.error = Some(e.to_string()),
|
||||
}
|
||||
} else {
|
||||
self.error = Some("no image to yank".into());
|
||||
}
|
||||
}
|
||||
Key::Character("p") | Key::Character("v") => {
|
||||
match match self.clipboard.take() {
|
||||
Some(c) => Ok(c),
|
||||
None => Clipboard::new(),
|
||||
} {
|
||||
Ok(mut clipboard) => {
|
||||
match clipboard.get_image().map(utils::rgbaimage_from_arboard) {
|
||||
Ok(image) => {
|
||||
self.error = None;
|
||||
self.clipboard = Some(clipboard);
|
||||
|
||||
self.info =
|
||||
Some(format!("{}x{}", image.width(), image.height(),));
|
||||
if image.dimensions() < (100, 100) {
|
||||
self.image_filter = widget::image::FilterMethod::Nearest;
|
||||
}
|
||||
self.image = Some(image);
|
||||
return self.allocate_image();
|
||||
}
|
||||
Err(e) => self.error = Some(e.to_string()),
|
||||
};
|
||||
self.clipboard = Some(clipboard);
|
||||
}
|
||||
Err(e) => self.error = Some(e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
// ignore unused keys
|
||||
_ => {}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,3 +5,6 @@
|
|||
'b' to toggle the bar
|
||||
's' to save the image
|
||||
'q' to quit
|
||||
|
||||
'y' or 'c' to yank
|
||||
'p' or 'v' to put
|
||||
|
|
|
|||
21
src/utils.rs
21
src/utils.rs
|
|
@ -1,4 +1,7 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use iced::widget;
|
||||
use image::{DynamicImage, ImageDecoder, ImageReader, ImageResult, RgbaImage};
|
||||
|
|
@ -52,3 +55,19 @@ pub const fn string_from_filter_type(f: widget::image::FilterMethod) -> &'static
|
|||
widget::image::FilterMethod::Nearest => "nearest neighbor",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arboard_from_rgbaimage<'a>(image: &'a RgbaImage) -> arboard::ImageData<'a> {
|
||||
arboard::ImageData {
|
||||
width: image.width() as usize,
|
||||
height: image.height() as usize,
|
||||
bytes: Cow::Borrowed(image.as_ref()),
|
||||
}
|
||||
}
|
||||
pub fn rgbaimage_from_arboard(image: arboard::ImageData) -> RgbaImage {
|
||||
RgbaImage::from_raw(
|
||||
image.width as u32,
|
||||
image.height as u32,
|
||||
image.bytes.into_owned(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue