From 6177c05b9e841a64d444c2ecabef5e12ef97aea9 Mon Sep 17 00:00:00 2001 From: EthanHealy01 Date: Sun, 21 Sep 2025 22:20:24 +0100 Subject: [PATCH] changes to preview calculations to make it more similar to the output --- .../tools/addStamp/StampPreview.tsx | 4 +- .../tools/addStamp/StampPreviewUtils.ts | 60 ++++++++----------- 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/frontend/src/components/tools/addStamp/StampPreview.tsx b/frontend/src/components/tools/addStamp/StampPreview.tsx index 66ad3c2f0..b6299f474 100644 --- a/frontend/src/components/tools/addStamp/StampPreview.tsx +++ b/frontend/src/components/tools/addStamp/StampPreview.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { AddStampParameters } from './useAddStampParameters'; import { pdfWorkerManager } from '../../../services/pdfWorkerManager'; import { useThumbnailGeneration } from '../../../hooks/useThumbnailGeneration'; -import { A4_ASPECT_RATIO, getFirstSelectedPage, getFontFamily, computeStampPreviewStyle } from './StampPreviewUtils'; +import { A4_ASPECT_RATIO, getFirstSelectedPage, getFontFamily, computeStampPreviewStyle, getAlphabetPreviewScale } from './StampPreviewUtils'; import styles from './StampPreview.module.css'; type Props = { @@ -281,7 +281,7 @@ export default function StampPreview({ parameters, onParameterChange, file, show className={styles.textLine} style={{ fontFamily: getFontFamily(parameters.alphabet), - fontSize: `${Math.max(1, parameters.fontSize / 2)}px`, + fontSize: `${Math.max(1, (parameters.fontSize * getAlphabetPreviewScale(parameters.alphabet)) / 2)}px`, whiteSpace: 'nowrap', }} > diff --git a/frontend/src/components/tools/addStamp/StampPreviewUtils.ts b/frontend/src/components/tools/addStamp/StampPreviewUtils.ts index 3ee7811ea..9197af318 100644 --- a/frontend/src/components/tools/addStamp/StampPreviewUtils.ts +++ b/frontend/src/components/tools/addStamp/StampPreviewUtils.ts @@ -50,6 +50,20 @@ export const getFirstSelectedPage = (input: string): number => { export type StampPreviewStyle = { container: any; item: any }; +// Unified per-alphabet preview adjustments +export type Alphabet = 'roman' | 'arabic' | 'japanese' | 'korean' | 'chinese' | 'thai'; +export type AlphabetTweaks = { scale: number; rowOffsetRem: [number, number, number]; lineHeight: number; capHeightRatio: number }; +export const ALPHABET_PREVIEW_TWEAKS: Record = { + // [top, middle, bottom] row offsets in rem + roman: { scale: 1.0/1.18, rowOffsetRem: [0, 1, 2.2], lineHeight: 1.28, capHeightRatio: 0.70 }, + arabic: { scale: 1.2, rowOffsetRem: [0, 1.5, 2.5], lineHeight: 1, capHeightRatio: 0.68 }, + japanese: { scale: 1/1.2, rowOffsetRem: [-0.1, 1, 2], lineHeight: 1, capHeightRatio: 0.72 }, + korean: { scale: 1.0/1.05, rowOffsetRem: [-0.2, 0.5, 1.4], lineHeight: 1, capHeightRatio: 0.72 }, + chinese: { scale: 1/1.2, rowOffsetRem: [0, 2, 2.8], lineHeight: 1, capHeightRatio: 0.72 }, + thai: { scale: 1/1.2, rowOffsetRem: [-1, 0, .8], lineHeight: 1, capHeightRatio: 0.66 }, +}; +export const getAlphabetPreviewScale = (alphabet: string): number => (ALPHABET_PREVIEW_TWEAKS as any)[alphabet]?.scale ?? 1.0; + export function computeStampPreviewStyle( parameters: AddStampParameters, imageMeta: ImageMeta, @@ -70,26 +84,9 @@ export function computeStampPreviewStyle( const marginPts = (widthPts + heightPts) / 2 * (marginFactorMap[parameters.customMargin] ?? 0.035); // Compute content dimensions - const heightPtsContent = parameters.fontSize; // UI size in points + const heightPtsContent = parameters.fontSize * getAlphabetPreviewScale(parameters.alphabet); let widthPtsContent = heightPtsContent; - // Approximate PDF cap height ratio per alphabet to mirror backend's calculateTextCapHeight usage - const getCapHeightRatio = (alphabet: string): number => { - switch (alphabet) { - case 'roman': - return 0.70; // Noto Sans/Helvetica ~0.7 em - case 'arabic': - return 0.68; - case 'thai': - return 0.66; - case 'japanese': - case 'korean': - case 'chinese': - return 0.72; // CJK glyph boxes - default: - return 0.70; - } - }; if (parameters.stampType === 'image' && imageMeta) { const aspect = imageMeta.width / imageMeta.height; @@ -109,8 +106,6 @@ export function computeStampPreviewStyle( // Convert measured px width back to PDF points using horizontal scale widthPtsContent = measuredWidthPx / scaleX; - // Empirical tweak to better match PDFBox string width for Roman fonts - // PDFBox often yields ~8-12% narrower widths than browser canvas for the same font family let adjustmentFactor = 1.0; switch (parameters.alphabet) { case 'roman': @@ -151,7 +146,7 @@ export function computeStampPreviewStyle( if (parameters.overrideX >= 0 && parameters.overrideY >= 0) return parameters.overrideY; // For text, backend positions using cap height, not full font size const heightForY = parameters.stampType === 'text' - ? heightPtsContent * getCapHeightRatio(parameters.alphabet) + ? heightPtsContent * ((ALPHABET_PREVIEW_TWEAKS as any)[parameters.alphabet]?.capHeightRatio ?? 0.70) : heightPtsContent; switch (Math.floor((position - 1) / 3)) { case 0: // Top @@ -167,31 +162,28 @@ export function computeStampPreviewStyle( const xPts = calcX(); const yPts = calcY(); - const xPx = xPts * scaleX; + let xPx = xPts * scaleX; let yPx = yPts * scaleY; - // Vertical correction: text appears lower in preview vs output for middle/bottom rows if (parameters.stampType === 'text') { try { const rootFontSizePx = parseFloat(getComputedStyle(document.documentElement).fontSize || '16') || 16; - const middleRowOffsetPx = 1 * rootFontSizePx; - const bottomRowOffsetPx = 1.25 * rootFontSizePx; - const rowIndex = Math.floor((position - 1) / 3); - if (rowIndex === 1) { - yPx += middleRowOffsetPx; - } else if (rowIndex === 2) { - yPx += bottomRowOffsetPx; - } + const rowIndex = Math.floor((position - 1) / 3); // 0 top, 1 middle, 2 bottom + const offsets = (ALPHABET_PREVIEW_TWEAKS as any)[parameters.alphabet]?.rowOffsetRem ?? [0, 0, 0]; + const offsetRem = offsets[rowIndex] ?? 0; + yPx += offsetRem * rootFontSizePx; } catch (e) { - console.error(e); + // no-op } } const widthPx = widthPtsContent * scaleX; const heightPx = heightPtsContent * scaleY; + xPx = Math.max(0, Math.min(xPx, pageWidthPx - widthPx)); + yPx = Math.max(0, Math.min(yPx, pageHeightPx - heightPx)); + const opacity = Math.max(0, Math.min(1, parameters.opacity / 100)); const displayOpacity = opacity; - // Horizontal alignment inside the preview item for text stamps let alignItems: 'flex-start' | 'center' | 'flex-end' = 'flex-start'; if (parameters.stampType === 'text') { const colIndex = position % 3; // 1: left, 2: center, 0: right @@ -229,7 +221,7 @@ export function computeStampPreviewStyle( display: 'flex', flexDirection: 'column', justifyContent: 'flex-start', - lineHeight: 1, + lineHeight: (ALPHABET_PREVIEW_TWEAKS as any)[parameters.alphabet]?.lineHeight ?? 1, alignItems, cursor: showQuickGrid ? 'default' : 'move', pointerEvents: showQuickGrid ? 'none' : 'auto',