fix apply
This commit is contained in:
BIN
public/fonts/Roboto-Regular.ttf
Normal file
BIN
public/fonts/Roboto-Regular.ttf
Normal file
Binary file not shown.
@@ -170,8 +170,8 @@ async fn export_batch(images: Vec<ExportImageTask>, watermark: WatermarkSettings
|
||||
let scaled_font = PxScale::from(scale_px);
|
||||
let (t_width, _t_height) = imageproc::drawing::text_size(scaled_font, &font, &watermark.text);
|
||||
|
||||
// 3. Ensure it fits width (Padding 10%)
|
||||
let max_width = (width as f32 * 0.90) as u32;
|
||||
// 3. Ensure it fits width (Padding 15%)
|
||||
let max_width = (width as f32 * 0.85) as u32;
|
||||
if t_width > max_width {
|
||||
let ratio = max_width as f32 / t_width as f32;
|
||||
scale_px *= ratio;
|
||||
@@ -395,8 +395,8 @@ async fn layout_watermark(path: String, text: String, base_scale: f64) -> Result
|
||||
let mut font_scale = PxScale::from(scale_px);
|
||||
let (mut t_width, mut t_height) = imageproc::drawing::text_size(font_scale, &font, &text);
|
||||
|
||||
// 3. Auto-Fit Width (Limit to 90% of image width)
|
||||
let max_width = (width as f32 * 0.90) as u32;
|
||||
// 3. Auto-Fit Width (Limit to 85% of image width)
|
||||
let max_width = (width as f32 * 0.85) as u32;
|
||||
if t_width > max_width {
|
||||
let ratio = max_width as f32 / t_width as f32;
|
||||
scale_val *= ratio as f64;
|
||||
@@ -411,9 +411,15 @@ async fn layout_watermark(path: String, text: String, base_scale: f64) -> Result
|
||||
let center_x = zca.x * width as f64;
|
||||
let center_y = zca.y * height as f64;
|
||||
|
||||
let half_w = t_width as f64 / 2.0;
|
||||
let half_h = t_height as f64 / 2.0;
|
||||
let padding = width as f64 * 0.02;
|
||||
// Add safety margin to measured text size (Renderer mismatch buffer)
|
||||
let safe_t_width = t_width as f64 * 1.05;
|
||||
let safe_t_height = t_height as f64 * 1.05;
|
||||
|
||||
let half_w = safe_t_width / 2.0;
|
||||
let half_h = safe_t_height / 2.0;
|
||||
|
||||
// Increase edge padding to 4%
|
||||
let padding = width as f64 * 0.04;
|
||||
|
||||
let min_x = half_w + padding;
|
||||
let max_x = width as f64 - half_w - padding;
|
||||
|
||||
@@ -265,7 +265,7 @@ const stopDrawing = () => {
|
||||
<!-- Text Watermark Overlay (Only in Add Mode) -->
|
||||
<div
|
||||
v-if="store.editMode === 'add' && store.watermarkSettings.text"
|
||||
class="absolute cursor-move select-none whitespace-nowrap font-sans font-medium"
|
||||
class="absolute cursor-move select-none whitespace-nowrap font-medium"
|
||||
:style="{
|
||||
left: (position.x * 100) + '%',
|
||||
top: (position.y * 100) + '%',
|
||||
@@ -274,6 +274,7 @@ const stopDrawing = () => {
|
||||
color: effectiveColor,
|
||||
/* Scale based on HEIGHT of the IMAGE */
|
||||
fontSize: (imageRect.height * effectiveScale) + 'px',
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
height: '0px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
||||
@@ -100,9 +100,9 @@ const applyAll = () => {
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
@click="store.recalcCurrentWatermark()"
|
||||
@click="store.recalcAllWatermarks()"
|
||||
class="bg-blue-600 hover:bg-blue-500 text-white p-2 rounded flex items-center justify-center transition-colors"
|
||||
title="Apply & Recalculate Layout"
|
||||
title="Apply & Recalculate Layout for ALL Images"
|
||||
>
|
||||
<RotateCw class="w-4 h-4" />
|
||||
</button>
|
||||
|
||||
@@ -118,23 +118,31 @@ export const useGalleryStore = defineStore("gallery", () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function recalcCurrentWatermark() {
|
||||
if (selectedIndex.value < 0 || !selectedImage.value) return;
|
||||
const img = selectedImage.value;
|
||||
async function recalcAllWatermarks() {
|
||||
if (images.value.length === 0) return;
|
||||
|
||||
try {
|
||||
const result = await invoke<{x: number, y: number, scale: number}>("layout_watermark", {
|
||||
path: img.path,
|
||||
text: watermarkSettings.value.text,
|
||||
baseScale: watermarkSettings.value.scale
|
||||
const text = watermarkSettings.value.text;
|
||||
const baseScale = watermarkSettings.value.scale;
|
||||
|
||||
// Process in batches to avoid overwhelming the backend
|
||||
const batchSize = 5;
|
||||
for (let i = 0; i < images.value.length; i += batchSize) {
|
||||
const batch = images.value.slice(i, i + batchSize).map(async (img, batchIdx) => {
|
||||
const globalIdx = i + batchIdx;
|
||||
try {
|
||||
const result = await invoke<{x: number, y: number, scale: number}>("layout_watermark", {
|
||||
path: img.path,
|
||||
text: text,
|
||||
baseScale: baseScale
|
||||
});
|
||||
|
||||
setImageManualPosition(globalIdx, result.x, result.y);
|
||||
setImageSetting(globalIdx, 'scale', result.scale);
|
||||
} catch (e) {
|
||||
console.error(`Layout failed for ${img.name}`, e);
|
||||
}
|
||||
});
|
||||
|
||||
// Apply to current image
|
||||
setImageManualPosition(selectedIndex.value, result.x, result.y);
|
||||
setImageSetting(selectedIndex.value, 'scale', result.scale);
|
||||
|
||||
} catch (e) {
|
||||
console.error("Layout failed", e);
|
||||
await Promise.all(batch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +200,6 @@ export const useGalleryStore = defineStore("gallery", () => {
|
||||
addMaskStroke,
|
||||
clearMask,
|
||||
detectWatermark,
|
||||
recalcCurrentWatermark
|
||||
recalcAllWatermarks
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/fonts/Roboto-Regular.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
Reference in New Issue
Block a user