diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 0cf76b9..968bd1d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -153,9 +153,9 @@ async fn export_batch(images: Vec, watermark: WatermarkSettings let mut base_img = dynamic_img.to_rgba8(); let (width, height) = base_img.dimensions(); - // 1. Calculate Font Scale - // watermark.scale is percentage of image height. e.g. 0.05 - let mut scale_px = height as f32 * watermark.scale as f32; + // 1. Calculate Font Scale based on Min Dimension (Consistent relative size) + let min_dim = width.min(height) as f32; + let mut scale_px = min_dim * watermark.scale as f32; // 2. Measure Text let scaled_font = PxScale::from(scale_px); @@ -176,7 +176,7 @@ async fn export_batch(images: Vec, watermark: WatermarkSettings } else { match calculate_zca_internal(&dynamic_img) { Ok(res) => (res.x, res.y), - Err(_) => (0.5, 0.96), + Err(_) => (0.5, 0.99), } }; @@ -188,7 +188,7 @@ async fn export_batch(images: Vec, watermark: WatermarkSettings let mut y = (center_y - (final_t_height as f64 / 2.0)) as i32; // 5. Boundary Clamping (Ensure text stays inside image with padding) - let padding = (height as f64 * 0.01).max(5.0) as i32; // 1% padding + let padding = (height as f64 * 0.005).max(2.0) as i32; // 0.5% padding, min 2px let max_x = (width as i32 - final_t_width as i32 - padding).max(padding); let max_y = (height as i32 - final_t_height as i32 - padding).max(padding); @@ -255,7 +255,7 @@ fn calculate_zca_internal(img: &image::DynamicImage) -> Result Result(null); const containerRef = ref(null); -const renderHeight = ref(0); +const renderRefSize = ref(0); // Min of width/height let resizeObserver: ResizeObserver | null = null; -const updateHeight = () => { +const updateSize = () => { if (imgRef.value) { - renderHeight.value = imgRef.value.clientHeight; + // Use the smaller dimension to calculate scale, matching backend logic + renderRefSize.value = Math.min(imgRef.value.clientWidth, imgRef.value.clientHeight); } }; onMounted(() => { resizeObserver = new ResizeObserver(() => { - updateHeight(); + updateSize(); }); }); @@ -33,8 +34,6 @@ watch(imgRef, (el) => { if (el && resizeObserver) { resizeObserver.disconnect(); // clear old resizeObserver.observe(el); - // Force update immediately - // Wait for load? ResizeObserver usually handles layout shifts } }); @@ -43,13 +42,11 @@ const position = computed(() => { if (store.watermarkSettings.manual_override) { return store.watermarkSettings.manual_position; } - return store.selectedImage?.zcaSuggestion ? { x: store.selectedImage.zcaSuggestion.x, y: store.selectedImage.zcaSuggestion.y } : { x: 0.5, y: 0.5 }; + // Default to bottom center if no ZCA or manual + return store.selectedImage?.zcaSuggestion ? { x: store.selectedImage.zcaSuggestion.x, y: store.selectedImage.zcaSuggestion.y } : { x: 0.5, y: 0.98 }; }); const onMouseDown = (e: MouseEvent) => { - // Only allow dragging if target is the watermark itself (or its child) - // Actually, user should be able to click watermark to start drag. - // e.preventDefault to stop image drag e.preventDefault(); isDragging.value = true; dragStart.value = { x: e.clientX, y: e.clientY }; @@ -69,12 +66,9 @@ const onMouseMove = (e: MouseEvent) => { let newX = position.value.x + deltaX; let newY = position.value.y + deltaY; - // Clamp logic (Simple 0-1 clamp for center point first) - // Ideally we should clamp so the box stays inside, but we don't know the exact text width in px easily here without measurement. - // For MVP, clamping center to [0, 1] is "safe enough" to prevent losing it, - // but user asked for "not exceeding boundary". - // Visual clamping: slightly inside 0-1. - const padding = 0.01; + // Clamp logic (Allow getting very close to edge, padding handled by visual/backend) + // Using small padding to prevent sticking perfectly to edge if not desired + const padding = 0.005; newX = Math.max(padding, Math.min(1 - padding, newX)); newY = Math.max(padding, Math.min(1 - padding, newY)); @@ -98,27 +92,28 @@ const onMouseLeave = () => {