phase 1 & 2 first

This commit is contained in:
Julian Freeman
2026-01-18 22:55:12 -04:00
parent 54c9474894
commit 8a92eea397
19 changed files with 6496 additions and 193 deletions

5392
src-tauri/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -18,8 +18,10 @@ crate-type = ["staticlib", "cdylib", "rlib"]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = [] }
tauri-plugin-opener = "2"
tauri = { version = "2", features = ["protocol-asset"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
image = "0.25"
rayon = "1.10"
tauri-plugin-dialog = "2"

View File

@@ -5,6 +5,6 @@
"windows": ["main"],
"permissions": [
"core:default",
"opener:default"
"dialog:default"
]
}

View File

@@ -1,14 +1,179 @@
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
use std::fs;
#[derive(serde::Serialize)]
struct ImageItem {
path: String,
name: String,
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
#[tauri::command]
fn scan_dir(path: String) -> Result<Vec<ImageItem>, String> {
let mut images = Vec::new();
let dir = fs::read_dir(&path).map_err(|e| e.to_string())?;
for entry in dir {
if let Ok(entry) = entry {
let path = entry.path();
if path.is_file() {
if let Some(ext) = path.extension() {
let ext_str = ext.to_string_lossy().to_lowercase();
if ["png", "jpg", "jpeg", "webp"].contains(&ext_str.as_str()) {
images.push(ImageItem {
path: path.to_string_lossy().to_string(),
name: path.file_name().unwrap_or_default().to_string_lossy().to_string(),
});
}
}
}
}
}
// Sort by name
images.sort_by(|a, b| a.name.cmp(&b.name));
Ok(images)
}
use image::GenericImageView;
use image::Pixel;
#[derive(serde::Serialize)]
struct ZcaResult {
x: f64,
y: f64,
zone: String,
}
#[tauri::command]
fn get_zca_suggestion(path: String) -> Result<ZcaResult, String> {
let img = image::open(&path).map_err(|e| e.to_string())?;
let (width, height) = img.dimensions();
let bottom_start_y = (height as f64 * 0.8) as u32;
let zone_height = height - bottom_start_y;
let zone_width = width / 3;
let zones = [
("Left", 0, bottom_start_y),
("Center", zone_width, bottom_start_y),
("Right", zone_width * 2, bottom_start_y),
];
let mut min_std_dev = f64::MAX;
let mut best_zone = "Center";
let mut best_pos = (0.5, 0.9); // Default center
for (name, start_x, start_y) in zones.iter() {
let mut luma_values = Vec::with_capacity((zone_width * zone_height) as usize);
for y in *start_y..height {
for x in *start_x..(*start_x + zone_width) {
if x >= width { continue; }
let pixel = img.get_pixel(x, y);
let rgb = pixel.to_rgb();
let luma = 0.299 * rgb[0] as f64 + 0.587 * rgb[1] as f64 + 0.114 * rgb[2] as f64;
luma_values.push(luma);
}
}
let count = luma_values.len() as f64;
if count == 0.0 { continue; }
let mean = luma_values.iter().sum::<f64>() / count;
let variance = luma_values.iter().map(|v| (v - mean).powi(2)).sum::<f64>() / count;
let std_dev = variance.sqrt();
if std_dev < min_std_dev {
min_std_dev = std_dev;
best_zone = name;
let center_x_px = *start_x as f64 + (zone_width as f64 / 2.0);
let center_y_px = *start_y as f64 + (zone_height as f64 / 2.0);
best_pos = (center_x_px / width as f64, center_y_px / height as f64);
}
}
Ok(ZcaResult {
x: best_pos.0,
y: best_pos.1,
zone: best_zone.to_string(),
})
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_dialog::init())
.invoke_handler(tauri::generate_handler![scan_dir, get_zca_suggestion])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@@ -18,7 +18,11 @@
}
],
"security": {
"csp": null
"csp": "default-src 'self'; img-src 'self' asset: https://asset.localhost",
"assetProtocol": {
"enable": true,
"scope": ["**"]
}
}
},
"bundle": {