-
Notifications
You must be signed in to change notification settings - Fork 4
/
lib.rs
139 lines (121 loc) · 3.79 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#![allow(clippy::not_unsafe_ptr_arg_deref)]
use anyhow::{anyhow, Result};
use arboard::{Clipboard, ImageData};
use deno_bindgen::deno_bindgen;
use image::*;
use std::{borrow::Cow, io, str};
#[deno_bindgen]
pub enum ClipboardResult {
Ok { data: Option<String> },
Error { error: String },
}
fn inner_get_image() -> Result<String> {
let mut clipboard = Clipboard::new()?;
let image = clipboard.get_image()?;
let image: RgbaImage =
ImageBuffer::from_raw(image.width as u32, image.height as u32, image.bytes.into())
.ok_or_else(|| anyhow!("image data size maybe too big/small"))?;
let mut out = io::Cursor::new(Vec::new());
image.write_to(&mut out, ImageOutputFormat::Png)?;
let data = out.get_ref().as_bytes();
let b64 = base64::encode(data);
Ok(b64)
}
#[deno_bindgen]
pub fn get_image() -> ClipboardResult {
match inner_get_image() {
Ok(data) => ClipboardResult::Ok { data: Some(data) },
Err(err) => ClipboardResult::Error {
error: err.to_string(),
},
}
}
fn inner_get_text() -> Result<String> {
let mut clipboard = Clipboard::new()?;
clipboard
.get_text()
.map_err(|x| -> anyhow::Error { anyhow!(x) })
}
#[deno_bindgen]
pub fn get_text() -> ClipboardResult {
match inner_get_text() {
Ok(data) => ClipboardResult::Ok { data: Some(data) },
Err(err) => ClipboardResult::Error {
error: err.to_string(),
},
}
}
fn inner_set_image(data: &[u8]) -> Result<()> {
let mut clipboard = Clipboard::new()?;
let img = image::load_from_memory(data)?;
let img_data = ImageData {
width: img.width() as usize,
height: img.height() as usize,
bytes: Cow::from(img.into_bytes()),
};
clipboard
.set_image(img_data)
.map_err(|x| -> anyhow::Error { anyhow!(x) })
}
#[deno_bindgen]
pub fn set_image(data: &[u8]) -> ClipboardResult {
match inner_set_image(data) {
Ok(_) => ClipboardResult::Ok { data: None },
Err(err) => ClipboardResult::Error {
error: err.to_string(),
},
}
}
pub fn inner_set_text(text: &str) -> Result<()> {
let mut clipboard = Clipboard::new()?;
clipboard
.set_text(text.to_string())
.map_err(|x| -> anyhow::Error { anyhow!(x) })
}
#[deno_bindgen]
pub fn set_text(text: &str) -> ClipboardResult {
match inner_set_text(text) {
Ok(_) => ClipboardResult::Ok { data: None },
Err(err) => ClipboardResult::Error {
error: err.to_string(),
},
}
}
#[cfg(test)]
mod test {
use std::{fs::File, io::Read, path::Path};
use super::*;
fn assert_image(raw: Vec<u8>) {
let png_header: Vec<u8> = vec![0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
let raw_header = &raw[..8];
assert_eq!(raw_header, png_header);
}
#[test]
fn read_write_text() {
if let Err(err) = inner_set_text("set text") {
panic!("cannot set text: {}", err);
};
match inner_get_text() {
Ok(text) => {
assert_eq!(text, "set text")
}
Err(err) => {
panic!("cannot get text: {}", err);
}
};
}
#[test]
fn read_write_image() {
let read_file = |path: &Path| -> Vec<u8> {
let mut file = File::open(path).expect("cannot open file");
let mut buffer = Vec::<u8>::new();
file.read_to_end(&mut buffer).expect("cannot read to end");
buffer
};
let path = Path::new("testdata/out.png");
inner_set_image(read_file(path).as_slice()).expect("cannot write image");
let b64 = inner_get_image().expect("cannot get image");
let raw = base64::decode(&b64).expect("cannot decode base64");
assert_image(raw)
}
}