fix: improve PDF export fidelity (LINE_SEG priority + HWPX adapter + font fallbacks)#813
fix: improve PDF export fidelity (LINE_SEG priority + HWPX adapter + font fallbacks)#813PhilipKim85 wants to merge 6 commits into
Conversation
When `svgs_to_pdf()` generates multi-page PDFs via `svg2pdf::to_chunk()`, the Form XObject BBox is set to the SVG viewport dimensions. However, some SVG content (especially clipPath rects) extends beyond the viewport, causing right-side content to be clipped by the BBox boundary. This fix scans each SVG page for `<rect>` elements whose `x + width` exceeds the viewport width, then expands the SVG viewport accordingly before calling `to_chunk()`. The page MediaBox remains at the original size (e.g., A4), so the expanded content is properly scaled to fit. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use HWP file's original LINE_SEG line_height/line_spacing values directly instead of recalculating from font metrics. This preserves 한컴오피스's exact page composition (line heights, page breaks). The previous code's Composer path would override LINE_SEG heights when raw_lh < max_font_size, causing accumulated differences in paragraph heights and incorrect page breaks. For HWPX files (which lack LINE_SEG data), falls back to Composer's calculated values. Also adds comprehensive Korean font-family fallback mappings for HY series, 한컴, 함초롬, and 휴먼 fonts to improve PDF rendering on systems with 한컴오피스 installed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Check LINE_SEG validity (line_height > 0) before trusting data - HWPX files have LINE_SEG entries with all zeros; fall back to Composer path for these - HWP binary files with valid LINE_SEG still get priority treatment for accurate page layout Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Apply convert_hwpx_to_hwp_ir() during from_bytes() for HWPX sources, ensuring SectionDef controls are inserted into paragraph controls before the first pagination/compose pass. Previously, the HWPX adapter was only called in export_hwp_with_adapter() (HWP save path). For PDF/SVG export, HWPX documents were missing SectionDef controls in paragraph.controls, which could cause the typesetter to misidentify section boundaries. Also adds apply_hwpx_adapter() public method for manual invocation and makes core field pub(crate) for binary access. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Expand needs_line_seg_reflow() to handle: empty line_segs, all-zero line_heights (not just single-entry with height=0) - Move normalize_hwpx_paragraphs() BEFORE reflow_zero_height_paragraphs() so char_shapes are populated before reflow uses them - These changes improve HWPX text measurement for table cell paragraphs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
HWPX parser may split text and TAC table into separate paragraphs, leaving the table in an empty-text paragraph. The previous inline check required text or 2+ tables, causing single TAC tables in empty paragraphs to be treated as block tables (rendering failure). Expand is_tac_table_inline() to accept single TAC tables whose width fits within seg_width, regardless of text presence. Also remove debug output from table_layout.rs. Analysis: HWPX table header text disappears because page composition differs (due to missing LINE_SEG), causing tables to split across page boundaries (PartialTable rows=0..1 / 1..3). The first partial (header row) ends up on the previous page where it may overflow. Root cause is HWPX LINE_SEG absence, not the inline check — but this fix improves TAC table handling generally. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@PhilipKim85 PR #798 이어 다시 기여해주셔서 감사합니다. PDF 출력 품질 개선은 본 프로젝트의 중요한 영역이라 환영합니다. 본 PR 영역 영역 점검 결과 본 환경 정책 영역 영역 정합하지 않는 5가지 영역이 있어, close 후 분리 PR 영역 영역 재제출 권장드립니다. 각 영역 영역 분리 PR 영역 영역 단계별 진행 시 안전하게 머지 가능합니다. 1. base = main → devel 변경 필수본 프로젝트 영역 영역 외부 컨트리뷰터 워크플로우 (CLAUDE.md 명시):
main 영역 영역 release cycle 영역 영역 직접 진입 영역 영역. 모든 분리 PR 영역 영역 devel base 영역 영역 재제출 부탁드립니다. 2. 폰트 fallback chain — Noto / Pretendard 추가 필수본 환경 폰트 정책 (
본 PR 영역 영역 fallback chain 영역 영역 한컴/HY/휴먼 상용 폰트만 영역 영역 — 사용자 환경 영역 영역 폰트 미설치 시 효과 부재 + 본 환경 정책 영역 영역 오픈소스 우선. 권장 fallback 패턴: "한컴바탕" → "한컴바탕, HCR Batang, Noto Serif KR, 바탕, serif"
"함초롬바탕" → "함초롬바탕, HCR Batang, Noto Serif KR, 바탕, serif"
"HY신명조" → "HY신명조, HYSinMyeongJo-Medium, Noto Serif KR, 바탕, serif"
"휴먼명조" → "휴먼명조, Noto Serif KR, 바탕, serif"
// ... 모든 한글 폰트 영역 영역 Noto Serif KR / Noto Sans KR / Pretendard 추가3. typeset.rs LINE_SEG 우선 —
|
| PR | 본질 |
|---|---|
| #621 | 다중 줄 가드 |
| #622 | 다단 vpos-reset 가드 |
| #627 | 글상자 ㉠ y 회귀 정정 |
| #632 | LAYOUT_DRIFT_SAFETY_PX 2회 차감 정정 |
| #636 | aift p4 목차 alignment + Issue #635 흡수 |
본 PR 영역 영역 has_valid_line_segs 가드 영역 영역 HWP LINE_SEG 영역 영역 무조건 우선 → 누적된 Composer 경로 정정 영역 영역 우회 → 광범위 회귀 위험.
본 환경 영역 영역 결정적 검증 표준:
cargo test --lib --release(1157+ tests, 회귀 0)scripts/svg_regression_diff.sh build devel HEAD(7 fixture / 170 페이지 / 회귀 0)- 컨트리뷰터 영역 영역 PR 다단 paragraph 내 vpos-reset 미처리 정정 (closes #619) #622 / fix: Task #520 partial revert restore — exam_science p2 7번 글상자 ㉠ 사각형 y 회귀 정정 (closes #624) #627 / Task #631: HWP 권위값 더블체크로 vpos-reset 인접 line 보존 #632 / Task #630: aift p4 목차
·포함 라인(페이지 표기)8.67px 좌측 이탈 정정 #636 사이클 영역 영역 160+ fixture / 1,000+ 페이지 sweep 결과 명시
본 PR 영역 영역 "Content Match ~88% (HWP) / ~64% (HWPX)" 영역 영역 정성적 측정만 — 본 환경 표준 영역 영역 광범위 sweep 결과 (정확 페이지 수 / 회귀 페이지 수 / 회귀 부재 입증) 영역 영역 필수.
4. Issue 연결 부재
본 환경 절차 (CLAUDE.md):
Issue → 브랜치 → 할일 → 계획서 → 구현 순서
각 분리 PR 영역 영역 GitHub Issue 영역 영역 본질 분리 + 본 환경 영역 영역 assign + PR 영역 영역 closes #N 연결 부탁드립니다.
5. wasm_api.rs::HwpDocument.core 가시성 변경
pub(crate) core 변경 영역 영역 API surface 영역 영역 노출 영역 영역. apply_hwpx_adapter 영역 영역 내부 영역 영역 호출 가능 영역 영역 영역 본 변경 영역 영역 필요 영역 영역 점검 필요. 가시성 영역 영역 영역 영역 영역 유지하고 메서드만 추가하는 패턴 권장.
분리 PR 가이드 (3 PR 권장)
분리 PR 1 — pdf.rs SVG viewport BBox 확장 (안전, 우선 권장)
scan_svg_max_x+expand_svg_viewport본질- PR fix: prevent PDF content clipping caused by BBox in multi-page export #798 close 후속 정합
- Issue 신규 — "BBox clipping prevent: SVG viewport expansion"
- 가장 안전한 영역 영역 우선 머지 가능
분리 PR 2 — 폰트 fallback (Noto/Pretendard 우선 + 한컴/HY 보조)
- pdf.rs
add_font_fallbacks영역 영역 본 환경 영역 영역 fallback 패턴 적용 - Issue 신규 — "Font fallback chain expansion for HWP/HWPX fonts"
분리 PR 3 — typeset.rs LINE_SEG 우선 + HWPX adapter
- 광범위 sweep 결과 + 회귀 0 입증 필수
- Issue 신규 — "LINE_SEG priority for HWP page layout fidelity"
- PR Task #617: 표 셀 padding shrink 휴리스틱 다중 줄 가드 (closes #617) #621/다단 paragraph 내 vpos-reset 미처리 정정 (closes #619) #622/fix: Task #520 partial revert restore — exam_science p2 7번 글상자 ㉠ 사각형 y 회귀 정정 (closes #624) #627/Task #631: HWP 권위값 더블체크로 vpos-reset 인접 line 보존 #632/Task #630: aift p4 목차
·포함 라인(페이지 표기)8.67px 좌측 이탈 정정 #636 정정 영역 영역 정합 확인
메모리 룰 정합
본 환경 영역 영역 검증 표준 영역 영역 정합 영역 영역 분리 PR 영역 영역 분명히 진행 가능합니다. PDF 품질 개선 본질 영역 영역 본 프로젝트 중요 방향 영역 영역 정합 — 적극 환영합니다.
본 PR close + 분리 PR 1 (SVG BBox) 영역 영역 영역 우선 부탁드립니다. 분리 PR 2/3 영역 영역 영역 영역 후속 진행 가능합니다.
수고하셨습니다.
- mydocs/pr/archives/pr_813_review.md (5 정책 위반 + 회귀 위험 분석) - mydocs/pr/archives/pr_813_report.md (옵션 C 처리 결과 + 분리 PR 가이드) - mydocs/orders/20260511.md PR #813 행 추가 핵심 문제점: 1. base=main 정책 위반 (devel 재제출 필수) 2. 폰트 라이선스 정책 어긋남 (Noto/Pretendard 미포함) 3. typeset.rs LINE_SEG 가드 회귀 위험 (PR #621/#622/#627/#632/#636 누적 정정 우회) 4. Issue 연결 부재 5. wasm_api.rs pub(crate) core 가시성 변경 분리 PR 3 가이드 (재제출 대기): - 분리 PR 1: pdf.rs SVG BBox (안전, PR #798 close 후속, 우선) - 분리 PR 2: 폰트 fallback (Noto/Pretendard 우선) - 분리 PR 3: typeset.rs LINE_SEG + HWPX adapter (광범위 sweep 필수)
Summary
Three improvements to PDF export quality:
1. Prioritize original LINE_SEG data in typesetter (
typeset.rs)line_height/line_spacingvalues directly instead of Composer recalculationline_height > 0)2. Apply HWPX adapter before initial pagination (
document.rs)convert_hwpx_to_hwp_ir()duringfrom_bytes()for HWPX sourcesControl::SectionDefis inserted into paragraph controls before first paginationexport_hwp_with_adapter()(HWP save path)3. Expand Korean font-family fallbacks (
pdf.rs)한컴바탕→HCR Batang)Test Results
Files Changed
src/renderer/typeset.rs— LINE_SEG validity check + prioritysrc/renderer/pdf.rs— Font fallback mappingssrc/document_core/commands/document.rs— HWPX adapter in from_bytessrc/wasm_api.rs—apply_hwpx_adapter()public method +pub(crate) core