image dir

This commit is contained in:
2026-03-07 17:45:21 +01:00
parent ab2c25f8dc
commit ff3f8f94ef
2 changed files with 66 additions and 43 deletions

View File

@ -1,6 +1,6 @@
use arboard::{Clipboard, ImageData};
use image::codecs::png::PngEncoder;
use image::{ExtendedColorType, ImageEncoder, ImageReader};
use image::{EncodableLayout, ExtendedColorType, ImageEncoder, ImageReader, math};
use rand::{RngExt, distr::Alphanumeric};
use serde::{Deserialize, Serialize};
use std::fs::{self, File};
@ -20,7 +20,7 @@ pub struct ClipboardEntry {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ClipboardData {
Text(String),
#[serde(with = "base64_vec")]
// #[serde(with = "base64_vec")]
Image(Vec<u8>),
}
@ -47,28 +47,28 @@ impl ClipboardHandler for Handler {
// Wayland
// Wayland end
mod base64_vec {
use base64::{Engine as _, engine::general_purpose::STANDARD};
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S: Serializer>(v: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error> {
let base64_str = STANDARD.encode(v);
serializer.serialize_str(&base64_str)
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
let base64_str = String::deserialize(deserializer)?;
match STANDARD.decode(base64_str) {
Ok(bytes) => Ok(bytes),
Err(error_base64) => {
let error_serde = serde::de::Error::custom(error_base64);
Err(error_serde)
}
}
}
}
// mod base64_vec {
// use base64::{Engine as _, engine::general_purpose::STANDARD};
// use serde::{Deserialize, Deserializer, Serializer};
// pub fn serialize<S: Serializer>(v: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error> {
// let base64_str = STANDARD.encode(v);
// serializer.serialize_str(&base64_str)
// }
// pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
// let base64_str = String::deserialize(deserializer)?;
// match STANDARD.decode(base64_str) {
// Ok(bytes) => Ok(bytes),
// Err(error_base64) => {
// let error_serde = serde::de::Error::custom(error_base64);
// Err(error_serde)
// }
// }
// }
// }
pub trait ImageDataExt {
fn to_png(&self) -> Result<Vec<u8>, Box<dyn Error>>;
fn save_img(bytes: Vec<u8>) -> Result<(), Box<dyn Error>>;
fn save_img(bytes: Vec<u8>, dir_path: &str) -> Result<(), Box<dyn Error>>;
}
impl ImageDataExt for ImageData<'_> {
@ -84,7 +84,7 @@ impl ImageDataExt for ImageData<'_> {
Ok(buffer)
}
fn save_img(bytes: Vec<u8>) -> Result<(), Box<dyn Error>> {
fn save_img(bytes: Vec<u8>, image_dir_path: &str) -> Result<(), Box<dyn Error>> {
let img = ImageReader::new(Cursor::new(&bytes))
.with_guessed_format()?
.decode()?;
@ -93,7 +93,7 @@ impl ImageDataExt for ImageData<'_> {
.take(16)
.map(char::from)
.collect();
img.save(format!("clipboard/{}.png", name))?;
img.save(format!("{}/{}.png", image_dir_path, name))?;
Ok(())
}
}
@ -129,29 +129,42 @@ impl ClipboardEntry {
})
}
pub fn init(path: &str) -> Result<(), Box<dyn Error>> {
if !std::fs::exists(path)? {
fs::create_dir(path)?;
pub fn init(dir_path: &str) -> Result<(), Box<dyn Error>> {
if !std::fs::exists(dir_path)? {
fs::create_dir(dir_path)?;
} else {
println!("Dir already exists.");
println!("{:?} dir already exists.", { dir_path });
}
let file = Path::new(path).join("clipboard.json");
ClipboardEntry::new_json(file.to_str().unwrap())?;
let image_path = format!("{}/images", dir_path);
if !std::fs::exists(&image_path)? {
fs::create_dir(&image_path)?;
} else {
println!("{:?} dir already exists.", { image_path });
}
let file_path = Path::new(dir_path).join("clipboard.json");
ClipboardEntry::new_json(file_path.to_str().unwrap())?;
Ok(())
}
pub fn new_json(path: &str) -> Result<(), Box<dyn Error>> {
if Path::new(path).exists() {
pub fn new_json(file_path: &str) -> Result<(), Box<dyn Error>> {
if Path::new(file_path).exists() {
Err("File already exists.".into())
} else {
File::create(path)?;
File::create(file_path)?;
Ok(())
}
}
pub fn append_json(&self, path: &str) -> Result<(), Box<dyn Error>> {
let mut entries: Vec<ClipboardEntry> = if Path::new(path).exists() {
let data = fs::read_to_string(path)?;
pub fn append_clipboard_history(
&self,
file_path: &str,
image_dir_path: &str,
) -> Result<(), Box<dyn Error>> {
let mut entries: Vec<ClipboardEntry> = if Path::new(file_path).exists() {
let data = fs::read_to_string(file_path)?;
if data.trim().is_empty() {
Vec::new()
} else {
@ -160,17 +173,26 @@ impl ClipboardEntry {
} else {
Vec::new()
};
entries.push(self.clone());
let json = serde_json::to_string_pretty(&entries)?;
fs::write(path, json)?;
match &self.content {
ClipboardData::Text(_) => {
entries.push(self.clone());
let json = serde_json::to_string_pretty(&entries)?;
fs::write(file_path, json)?;
}
ClipboardData::Image(image) => {
<ImageData<'_> as ImageDataExt>::save_img(image.to_vec(), image_dir_path)?;
}
}
Ok(())
}
pub fn read_json(path: &str) -> Result<Vec<ClipboardEntry>, Box<dyn Error>> {
if !Path::new(path).exists() {
pub fn read_text_history_json(file_path: &str) -> Result<Vec<ClipboardEntry>, Box<dyn Error>> {
if !Path::new(file_path).exists() {
return Ok(Vec::new());
}
let data = fs::read_to_string(path)?;
let data = fs::read_to_string(file_path)?;
if data.trim().is_empty() {
return Ok(Vec::new());
}

View File

@ -5,11 +5,12 @@ use std::error::Error;
use std::sync::mpsc::channel;
// X11
#[cfg(feature = "x11")]
// #[cfg(feature = "x11")]
fn main() -> Result<(), Box<dyn Error>> {
let mut clipboard = Clipboard::new()?;
let dir_path = "clipboard";
let file_path = "clipboard/clipboard.json";
let image_dir_path = "clipboard/images/";
ClipboardEntry::init(dir_path).unwrap_or(());
let (tx, rx) = channel();
@ -27,7 +28,7 @@ fn main() -> Result<(), Box<dyn Error>> {
for _ in rx {
println!("Clipboard changed!");
if let Ok(entry) = ClipboardEntry::new(&mut clipboard) {
if let Err(e) = entry.append_json(file_path) {
if let Err(e) = entry.append_clipboard_history(file_path, image_dir_path) {
eprintln!("JSON writing error: {}", e);
} else {
println!("JSON edited!");