From 1171101166b19875ebdb09fca4b24a8dc05cc7e5 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 16:43:41 +0000 Subject: [PATCH] Fix font/size preservation and startup freeze - WYSIWYG editor: Calculate per-line line-heights based on original PDF spacing (gap between lines) instead of uniform height. Each line now gets its own advance value, preserving the exact layout when editing multi-line text with different font sizes (e.g., 22pt heading + 16pt body). - Startup freeze: Make organize_identity_plan non-blocking. Initialize pagePlan with default identity immediately, then load the real plan in the background. This prevents the UI from freezing when opening large PDFs while PDFium processes all pages. Co-Authored-By: Claude Haiku 4.5 Claude-Session: https://claude.ai/code/session_01HgnbPwSoRGNH7LHsDUmRpk --- app/src/main.js | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/app/src/main.js b/app/src/main.js index 5f285ba..65f6db7 100644 --- a/app/src/main.js +++ b/app/src/main.js @@ -107,7 +107,14 @@ async function loadDocument(path) { updateCurrentPage(); updateZoomLabel(); - state.pagePlan = await invoke("organize_identity_plan", { path: state.path, password: null }).catch(() => []); + // Khởi tạo plan mặc định ngay (tất cả trang theo thứ tự gốc). + // Load plan thực tế ở background để không block UI khi mở file. + state.pagePlan = state.pages.map((p) => ({ page: p.index, rotate: 0 })); + invoke("organize_identity_plan", { path: state.path, password: null }) + .then((plan) => { + state.pagePlan = plan; + }) + .catch(() => {}); state.orgSelected = new Set(); state.orgAnchor = null; state.orgThumbs = new Map(); @@ -2525,24 +2532,41 @@ function startBlockTextEdit(o, lines, ev) { // còn bbox PDF ôm sát glyph → đẩy khung lên (advPx − cỡ chữ)/2 cho trùng. const fs0 = (lines[0].fs || o.font_size || 12) * s; const topPx = Math.max(0, (p.heightPt - union.top) * s - Math.max(0, (advPx - fs0) / 2)); + // Tính advance cho TỪNG DÒNG dựa trên vị trí gốc trong PDF để giữ layout. + const perLineAdvances = []; + for (let i = 0; i < lines.length; i++) { + let linAdvPx; + if (i < lines.length - 1) { + // Advance = khoảng cách giữa dòng này và dòng tiếp theo (giữ nguyên từ PDF). + const gap = lines[i].rect.bottom - lines[i + 1].rect.top; + linAdvPx = Math.max(8, gap * s); + } else { + // Dòng cuối: dùng cỡ chữ × 1.25. + linAdvPx = Math.max(8, (lines[i].fs || 12) * s * 1.25); + } + perLineAdvances.push(linAdvPx); + } + const totalHeightPx = perLineAdvances.reduce((a, b) => a + b, 0); + Object.assign(ce.style, { left: leftPt * s + "px", top: topPx + "px", width: widthPt * s + "px", - minHeight: lines.length * advPx + 4 + "px", + minHeight: totalHeightPx + 4 + "px", textAlign: centered ? "center" : "left", }); - // MỖI DÒNG 1 div với đúng cỡ/màu/kiểu của dòng đó (WYSIWYG khi gõ). - for (const l of lines) { + for (let i = 0; i < lines.length; i++) { + const l = lines[i]; const rep = l.runs.find((r) => (r.text || "").trim()) || l.runs[0] || o; const div = document.createElement("div"); div.className = "edit-line"; const t = composeLineText(l.runs); if (t) div.textContent = t; else div.innerHTML = "
"; - div.style.fontSize = Math.max(6, (l.fs || 12) * s) + "px"; - div.style.lineHeight = advPx + "px"; + const divFs = Math.max(6, (l.fs || 12) * s); + div.style.fontSize = divFs + "px"; + div.style.lineHeight = perLineAdvances[i] + "px"; div.style.fontFamily = cssFontStack(rep.font_family || o.font_family); div.style.fontWeight = (rep.font_bold != null ? rep.font_bold : o.font_bold) ? "bold" : "normal"; div.style.fontStyle = (rep.font_italic != null ? rep.font_italic : o.font_italic) ? "italic" : "normal";