diff --git a/src/background/gamemap.rs b/src/background/gamemap.rs index 1c34691..2a9a19a 100644 --- a/src/background/gamemap.rs +++ b/src/background/gamemap.rs @@ -48,7 +48,7 @@ pub fn generate_map( } /// https://github.com/NullCascade/morrowind-mods/blob/master/User%20Interface%20Expansion/plugin_source/PatchWorldMap.cpp#L158 -pub fn get_map_color(h: f32) -> Color32 { +fn get_map_color(h: f32) -> Color32 { #[derive(Default)] struct MyColor { pub r: f32, diff --git a/src/errors.rs b/src/errors.rs deleted file mode 100644 index 37f9669..0000000 --- a/src/errors.rs +++ /dev/null @@ -1,12 +0,0 @@ -use std::fmt; - -#[derive(Debug)] -pub struct SizeMismatchError; - -impl fmt::Display for SizeMismatchError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Image sizes do not match!") - } -} - -impl std::error::Error for SizeMismatchError {} diff --git a/src/lib.rs b/src/lib.rs index e51469b..5cdac52 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ use std::{ }; use egui::{Color32, ColorImage, Pos2}; -use errors::SizeMismatchError; use image::{ error::{ImageFormatHint, UnsupportedError, UnsupportedErrorKind}, DynamicImage, ImageError, RgbaImage, @@ -28,7 +27,6 @@ mod app; mod background; mod dimensions; mod eframe_app; -mod errors; mod overlay; mod views; @@ -233,21 +231,7 @@ fn overlay_colors_with_alpha(color1: Color32, color2: Color32, alpha1: f32) -> C Color32::from_rgba_premultiplied(r, g, b, 255) } -fn overlay_colors(color1: Color32, color2: Color32) -> Color32 { - let alpha1 = color1.a() as f32 / 255.0; - let alpha2 = color2.a() as f32 / 255.0; - - let r = ((1.0 - alpha2) * (alpha1 * color1.r() as f32 + alpha2 * color2.r() as f32)) as u8; - let g = ((1.0 - alpha2) * (alpha1 * color1.g() as f32 + alpha2 * color2.g() as f32)) as u8; - let b = ((1.0 - alpha2) * (alpha1 * color1.b() as f32 + alpha2 * color2.b() as f32)) as u8; - let a = alpha1 * 255.0; // TODO HACK - - Color32::from_rgba_premultiplied(r, g, b, a as u8) -} - -fn save_image(path: &Path, color_image: &ColorImage) -> Result<(), ImageError> { - // get image - +fn color_image_to_dynamic_image(color_image: &ColorImage) -> Result { let pixels = color_image.as_raw(); // Create an RgbaImage from the raw pixel data @@ -257,9 +241,7 @@ fn save_image(path: &Path, color_image: &ColorImage) -> Result<(), ImageError> { pixels.to_vec(), ) { // Convert the RgbaImage to a DynamicImage (required for saving as PNG) - let dynamic_img = DynamicImage::ImageRgba8(img); - dynamic_img.save(path)?; - Ok(()) + Ok(DynamicImage::ImageRgba8(img)) } else { let e = ImageError::Unsupported(UnsupportedError::from_format_and_kind( ImageFormatHint::Name("".to_owned()), @@ -328,30 +310,6 @@ fn calculate_dimensions( } } -pub fn get_layered_image( - img: ColorImage, - img2: ColorImage, -) -> Result { - if img.size != img2.size { - return Err(SizeMismatchError); - } - - // base image - let mut layered = img.pixels.clone(); - - // overlay second image - for (i, color1) in img.pixels.into_iter().enumerate() { - let color2 = img2.pixels[i]; - layered[i] = overlay_colors(color1, color2); - } - - // create new colorImage - Ok(ColorImage { - pixels: layered, - size: img.size, - }) -} - fn load_texture(data_files: &Option, ltex: &LandscapeTexture) -> Option { let data_files = data_files.as_ref()?; diff --git a/src/views/map_view.rs b/src/views/map_view.rs index 41ad67a..e041a15 100644 --- a/src/views/map_view.rs +++ b/src/views/map_view.rs @@ -1,6 +1,7 @@ use eframe::emath::{pos2, Pos2, Rect, RectTransform}; use eframe::epaint::{Color32, Rounding, Shape, Stroke}; use egui::Sense; +use image::{imageops, ImageError}; use log::info; use crate::app::TooltipInfo; @@ -11,7 +12,7 @@ use crate::overlay::paths; use crate::overlay::regions::get_region_shapes; use crate::overlay::travel::get_travel_shapes; use crate::{ - get_layered_image, height_from_screen_space, save_image, CellKey, EBackground, TemplateApp, + color_image_to_dynamic_image, height_from_screen_space, CellKey, EBackground, TemplateApp, GRID_SIZE, VERTEX_CNT, }; @@ -284,7 +285,12 @@ impl TemplateApp { ui.separator(); if ui.button("Save as image").clicked() { - self.save_image(ctx); + match self.save_image(ctx) { + Ok(_) => {} + Err(e) => { + info!("Error saving image: {:?}", e); + } + } ui.close_menu(); } @@ -308,7 +314,7 @@ impl TemplateApp { } } - fn save_image(&mut self, ctx: &egui::Context) { + fn save_image(&mut self, ctx: &egui::Context) -> Result<(), ImageError> { // construct default name from the first plugin name then the background type abbreviated let background_name = match self.ui_data.background { EBackground::None => "", @@ -333,49 +339,64 @@ impl TemplateApp { .save_file(); if let Some(original_path) = file_option { - let mut image = None; + let mut background = None; match self.ui_data.background { EBackground::None => {} EBackground::Landscape => { let max_texture_side = ctx.input(|i| i.max_texture_side); self.populate_texture_map(max_texture_side); - image = Some(self.get_landscape_image()); + background = Some(self.get_landscape_image()); } EBackground::HeightMap => { - image = Some(self.get_heightmap_image()); + background = Some(self.get_heightmap_image()); } EBackground::GameMap => { - image = Some(self.get_gamemap_image()); + background = Some(self.get_gamemap_image()); } } - if let Some(image) = image { - // TODO save shape overlays - let size_image = image.size; - let paths = paths::get_overlay_path_image(&self.dimensions, &self.land_records); - let size_paths = paths.size; + if let Some(bg) = background { + let mut bg_image = color_image_to_dynamic_image(&bg)?; + + if self.ui_data.overlay_paths { + let fg = paths::get_overlay_path_image(&self.dimensions, &self.land_records); + let mut fg_image = color_image_to_dynamic_image(&fg)?; + + #[allow(clippy::comparison_chain)] + if bg.size < fg.size { + // resize the smaller image to the larger image + bg_image = image::imageops::resize( + &bg_image, + fg.size[0] as u32, + fg.size[1] as u32, + image::imageops::FilterType::CatmullRom, + ) + .into(); + } else if bg.size > fg.size { + // resize the fg image to the bg image + fg_image = image::imageops::resize( + &fg_image, + bg.size[0] as u32, + bg.size[1] as u32, + image::imageops::FilterType::CatmullRom, + ) + .into(); + } - info!("Image size: {:?}", size_image); - info!("Paths size: {:?}", size_paths); + // overlay the images + imageops::overlay(&mut bg_image, &fg_image, 0, 0); + } - let msg = match get_layered_image(image, paths) { - Ok(r) => match save_image(&original_path, &r) { - Err(e) => format!("Error saving image: {}", e), - Ok(_) => { - format!("Image saved to: {}", original_path.display()) - } - }, - Err(err) => { - format!("Error saving image: {:?}", err) - } - }; + bg_image.save(original_path)?; rfd::MessageDialog::new() .set_title("Info") - .set_description(msg) + .set_description("Image saved successfully") .set_buttons(rfd::MessageButtons::Ok) .show(); } } + + Ok(()) } }