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 scaled_font = PxScale::from(scale_px);
|
||||||
let (t_width, _t_height) = imageproc::drawing::text_size(scaled_font, &font, &watermark.text);
|
let (t_width, _t_height) = imageproc::drawing::text_size(scaled_font, &font, &watermark.text);
|
||||||
|
|
||||||
// 3. Ensure it fits width (Padding 10%)
|
// 3. Ensure it fits width (Padding 15%)
|
||||||
let max_width = (width as f32 * 0.90) as u32;
|
let max_width = (width as f32 * 0.85) as u32;
|
||||||
if t_width > max_width {
|
if t_width > max_width {
|
||||||
let ratio = max_width as f32 / t_width as f32;
|
let ratio = max_width as f32 / t_width as f32;
|
||||||
scale_px *= ratio;
|
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 font_scale = PxScale::from(scale_px);
|
||||||
let (mut t_width, mut t_height) = imageproc::drawing::text_size(font_scale, &font, &text);
|
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)
|
// 3. Auto-Fit Width (Limit to 85% of image width)
|
||||||
let max_width = (width as f32 * 0.90) as u32;
|
let max_width = (width as f32 * 0.85) as u32;
|
||||||
if t_width > max_width {
|
if t_width > max_width {
|
||||||
let ratio = max_width as f32 / t_width as f32;
|
let ratio = max_width as f32 / t_width as f32;
|
||||||
scale_val *= ratio as f64;
|
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_x = zca.x * width as f64;
|
||||||
let center_y = zca.y * height as f64;
|
let center_y = zca.y * height as f64;
|
||||||
|
|
||||||
let half_w = t_width as f64 / 2.0;
|
// Add safety margin to measured text size (Renderer mismatch buffer)
|
||||||
let half_h = t_height as f64 / 2.0;
|
let safe_t_width = t_width as f64 * 1.05;
|
||||||
let padding = width as f64 * 0.02;
|
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 min_x = half_w + padding;
|
||||||
let max_x = width as f64 - 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) -->
|
<!-- Text Watermark Overlay (Only in Add Mode) -->
|
||||||
<div
|
<div
|
||||||
v-if="store.editMode === 'add' && store.watermarkSettings.text"
|
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="{
|
:style="{
|
||||||
left: (position.x * 100) + '%',
|
left: (position.x * 100) + '%',
|
||||||
top: (position.y * 100) + '%',
|
top: (position.y * 100) + '%',
|
||||||
@@ -274,6 +274,7 @@ const stopDrawing = () => {
|
|||||||
color: effectiveColor,
|
color: effectiveColor,
|
||||||
/* Scale based on HEIGHT of the IMAGE */
|
/* Scale based on HEIGHT of the IMAGE */
|
||||||
fontSize: (imageRect.height * effectiveScale) + 'px',
|
fontSize: (imageRect.height * effectiveScale) + 'px',
|
||||||
|
fontFamily: 'Roboto, sans-serif',
|
||||||
height: '0px',
|
height: '0px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|||||||
@@ -100,9 +100,9 @@ const applyAll = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<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"
|
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" />
|
<RotateCw class="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -118,23 +118,31 @@ export const useGalleryStore = defineStore("gallery", () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function recalcCurrentWatermark() {
|
async function recalcAllWatermarks() {
|
||||||
if (selectedIndex.value < 0 || !selectedImage.value) return;
|
if (images.value.length === 0) return;
|
||||||
const img = selectedImage.value;
|
|
||||||
|
|
||||||
try {
|
const text = watermarkSettings.value.text;
|
||||||
const result = await invoke<{x: number, y: number, scale: number}>("layout_watermark", {
|
const baseScale = watermarkSettings.value.scale;
|
||||||
path: img.path,
|
|
||||||
text: watermarkSettings.value.text,
|
// Process in batches to avoid overwhelming the backend
|
||||||
baseScale: watermarkSettings.value.scale
|
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);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
await Promise.all(batch);
|
||||||
// Apply to current image
|
|
||||||
setImageManualPosition(selectedIndex.value, result.x, result.y);
|
|
||||||
setImageSetting(selectedIndex.value, 'scale', result.scale);
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Layout failed", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,6 +200,6 @@ export const useGalleryStore = defineStore("gallery", () => {
|
|||||||
addMaskStroke,
|
addMaskStroke,
|
||||||
clearMask,
|
clearMask,
|
||||||
detectWatermark,
|
detectWatermark,
|
||||||
recalcCurrentWatermark
|
recalcAllWatermarks
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1 +1,8 @@
|
|||||||
@import "tailwindcss";
|
@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