render: add native Skia PNG raster backend#599
render: add native Skia PNG raster backend#599seo-rii wants to merge 9 commits intoedwardkim:develfrom
Conversation
PR #599 (refs #536, @seo-rii) 1차 검토 — render P4 native Skia PNG raster backend: - 본 환경 정체성 정합 (project_dtp_identity — DTP 엔진 + 다층 레이어 토대) - PR base skew 73 commits (eaac8bd, 5/4 PR #563 후속) — 단순 머지 시 본 사이클 cherry-pick 처리분 모두 revert 위험 - 그러나 본질 영역 (src/renderer/skia/ + layer_renderer.rs + image_conv.rs) 이 본 사이클 처리분과 0 중첩 → commit 단위 cherry-pick 가능 - 9 commits 순차 cherry-pick test: 모두 충돌 0 + cargo test --lib --release 1134 passed (회귀 0) + cargo test --features native-skia skia 20 passed + clippy 0건 - native-skia feature gate (기본 빌드 영향 없음, opt-in) 권장 처리: 옵션 A — 9 commits 순차 cherry-pick (단순 머지 절대 금지) + 결정적 검증 + Skia feature 테스트 + WASM check + PNG 내보내기 게이트웨이.
…션 + export-png CLI + 매뉴얼 PR #599 (Task #588 후속, refs #536) 의 Skia native PNG raster backend cherry-pick 후 메인테이너 정정 영역. 5개 영역 정합 처리: 1. **Skia 한글 폰트 fallback chain** (renderer.rs): - Noto Sans KR / Noto Serif KR / Nanum / Apple SD Gothic Neo / Apple Myungjo / Batang / 바탕 / Malgun Gothic / 맑은 고딕 등 추가 - SVG 의 CSS font chain 과 동일한 한글 폴백 폰트 순서 2. **--font-path 동적 폰트 로딩** (with_font_paths API): - SkiaLayerRenderer 에 custom_typefaces HashMap 추가 - ttfs 디렉토리의 한컴 전용 폰트 (HY견명조 등) 동적 로드 - SVG 의 --font-path 와 동일 패턴 3. **char 단위 fallback 렌더링** (공백 두부 정정): - text 를 char 단위로 분해, primary typeface 가 글리프 미보유 (unichar_to_glyph==0) 시 chain 의 다른 typeface 시도 - 모두 미보유 시 visible 글리프 그리지 않음 (NBSP/U+2007/U+200B 등 두부 방지) - measure_str 으로 정확한 advance 진행 4. **VLM 옵션 (AI 파이프라인 + Vision-Language Model 연동)**: - --vlm-target claude (1568 longest edge / 1.15 MP, Claude Vision 정합) - --scale <배율> (직접 배율) - --max-dimension <픽셀> (한 변 한도, 자동 scale 계산) - max_dimension + max_pixels 결합 자동 scale + 0.995 안전 마진 - PngExportOptions / VlmTarget 타입 정의 5. **export-png CLI 명령** (main.rs): - --output / --page / --font-path / --scale / --max-dimension / --vlm-target - native-skia feature gate (기본 빌드 영향 0) - DocumentCore::render_page_png_native_with_export_options API 호출 6. **매뉴얼 (한글 + 영문 동기화)**: - mydocs/manual/export_png_command.md - mydocs/eng/manual/export_png_command.md 7. **PNG 게이트웨이 도구**: - examples/pr599_png_gateway.rs 후속 이슈: - #613 (VLM 프리셋 확장 — GPT-4V / Gemini / Qwen-VL / LLaVA) - #614 (DPI 메타데이터 옵션 — PNG pHYs chunk) 검증: - cargo test --lib --release 1134 passed (회귀 0) - cargo test --features native-skia skia 20 passed - cargo clippy --release --features native-skia 0건 - 광범위 페이지네이션 회귀 sweep: 164 fixture / 1,614 페이지 / 회귀 0 - VLM 옵션 게이트웨이: 5개 옵션 조합 모두 정상 동작 (Claude 1.14M ≤ 1.15M ✓) - 시각 판정 ★ 통과 (SVG/PNG 한글 + 공백 정상 표시)
…efs #536 — @seo-rii 9 commits + 5개 영역 정정 + 시각 판정 ★ 통과) PR #599 (refs #536, @seo-rii) — render P4 native Skia PNG raster backend: - Skia 본질 cherry-pick (9 commits): src/renderer/skia/ + layer_renderer.rs + image_conv.rs 신규 영역 (본 사이클 처리분과 0 중첩) - 메인테이너 후속 정정 (5개 영역): 1. Skia 한글 fallback chain (Noto Sans KR / Nanum 등) 2. --font-path 동적 로딩 (with_font_paths API, SVG 패턴 정합) 3. char 단위 fallback (공백 두부 정정 — NBSP/U+2007/U+200B 방지) 4. VLM 옵션 (--vlm-target claude + --scale + --max-dimension, AI 파이프라인 + Vision-Language Model 연동) 5. export-png CLI 명령 + 매뉴얼 (한글 + 영문 동기화) 검증: - cargo test --lib --release 1134 passed (회귀 0) - cargo test --features native-skia skia 20 passed - clippy 0건 - WASM 4,581,465 bytes (PR #593 baseline +0 — feature gate 정합 입증) - 광범위 페이지네이션 회귀 sweep: 164 fixture / 1,614 페이지 / 회귀 0 - VLM 옵션 게이트웨이: Claude 898×1269 = 1.14 MP ≤ 1.15 MP ✓ 후속 이슈 등록: - #613 (VLM 프리셋 확장 — GPT-4V / Gemini / Qwen-VL / LLaVA) - #614 (DPI 메타데이터 옵션 — PNG pHYs chunk) 시각 판정 ★ 통과 (SVG/PNG 한글 + 공백 정상 표시). refs #536 (멀티 렌더러 지원 트래킹 이슈, OPEN 유지).
|
@seo-rii Thanks for the P4 stage — native Skia PNG raster backend ✨ The 9 essential commits have been cherry-picked into devel ( Merged
Maintainer follow-up fixes (
|
|
영문 댓글로 답변드린 점 양해 부탁드립니다 — 본 프로젝트 컨트리뷰터 분들께는 한글로 답변드리는 것이 정합인데, 본 PR 의 본질 영역이 영문 코드/주석 중심이라 영문으로 작성했습니다. 한글로도 같이 정리해드립니다. 처리 결과@seo-rii 님 P4 단계 (native Skia PNG raster backend) cherry-pick 완료되었습니다 (devel merge Cherry-pick
결정적 검증
메인테이너 후속 정정 (5개 영역, `876d820`)PR #599 본질만으로는 본 환경 한컴 fixture 가 정상 표시되지 않아 5개 영역 추가 정정. 향후 PR 에서 같은 패턴 적용에 참고 부탁드립니다. 1. Skia 한글 폰트 fallback chain (`renderer.rs::draw_text`)`4cf787f` (use font fallback in native skia text) 의 `["DejaVu Sans", "Arial", "sans-serif"]` chain 에 한글 폰트 추가 — Noto Sans KR / Noto Serif KR / Nanum Gothic / Nanum Myeongjo / Malgun Gothic / 맑은 고딕 / Batang / 바탕 / Apple SD Gothic Neo / AppleMyungjo 등. → SVG 의 CSS font chain 과 동일 패턴. CharShape.font_family (HY견명조 등) 가 시스템에 없을 때 한글 글리프 미보유 폰트로 fallback → 사각형(豆腐) 표시 결함 정정. 2. `--font-path` 동적 폰트 로딩 (`with_font_paths` API)`SkiaLayerRenderer::with_font_paths(&[PathBuf])` 추가:
3. char 단위 fallback (공백 두부 정정)단일 `canvas.draw_str(text, ...)` 호출이 NBSP (U+00A0) / FIGURE SPACE (U+2007) / ZERO WIDTH SPACE (U+200B) 등을 두부로 표시. char 단위 loop 으로 변경 — primary typeface 가 글리프 미보유 (`unichar_to_glyph==0`) 시 chain 의 다른 typeface 시도, 모두 미보유 시 visible glyph 그리지 않고 일반 공백 너비로 advance. 4. VLM 옵션 (AI 파이프라인 + Vision-Language Model 연동)`PngExportOptions` + `VlmTarget::Claude` 추가: ```bash 자동 scale 계산 — max_dimension + max_pixels 결합 (둘 다 한도 안) + 0.5% 안전 마진 (ceil + 부동소수점 오차). 다른 VLM 프리셋 (GPT-4V / Gemini / Qwen-VL / LLaVA) 은 #613 후속 task. 5. `export-png` CLI 명령 + 매뉴얼`src/main.rs::export_png` 추가 (native-skia feature gate, 기본 빌드 영향 0). 매뉴얼:
`--dpi` PNG pHYs chunk 메타데이터는 #614 후속 task. 향후 P5+ 단계 참고PR 본문 §"비목표" 영역 (complex text shaping parity / 완전한 equation native replay / CanvasKit / Skia visual regression fixture pipeline) 은 그대로 유지. 위 5개 영역은 본 환경 PNG backend 가 사용 가능한 수준으로 만들기 위한 최소 정합이며, 더 광범위한 text shaping (kerning / GSUB / GPOS) 작업은 별도 영역으로 정합. `unichar_to_glyph` per-char fallback 방식이 Skia 의 `make_text_blob` shaping 또는 harfbuzz 통합과 비교해서 더 좋은 idiomatic 패턴이 있다면 알려주세요. 향후 다시 검토 가능합니다. P3 (PR #498) → P4 (본 PR) 흐름의 일관성 + DTP 엔진 정체성 (`project_dtp_identity` — 다층 레이어 / WebGPU / 마스터 페이지 인프라 토대) 정합 우수했습니다. 감사합니다. |
- 처리 보고서 추가: mydocs/pr/archives/pr_599_report.md PR #599 (refs #536, @seo-rii) commit 단위 cherry-pick 9 commits + 메인테이너 5개 후속 정정 (한글 fallback / font-path / char-fallback / VLM 옵션 / export-png CLI + 매뉴얼) + 결정적 검증 + WASM 4,581,465 bytes + 광범위 페이지네이션 sweep (164 fixture / 1,614 페이지 / 회귀 0) + VLM 옵션 게이트웨이 + 시각 판정 ★ 통과 - 검토 보고서 archives 이동: mydocs/pr/pr_599_review.md → mydocs/pr/archives/pr_599_review.md - 5/5 orders 갱신: PR #599 항목 추가 - 컨트리뷰터에게 한글 댓글 추가 등록 (작업지시자 안내 정합) - 후속 이슈 #613 (VLM 프리셋 확장) / #614 (DPI 메타데이터) 등록 완료
…드 실패 정정) PR #599 후속 정정 commit (876d820) 으로 추가된 examples/pr599_png_gateway.rs 가 DocumentCore::render_page_png_native API 사용. 이 API 는 #[cfg(all(not(target_arch = "wasm32"), feature = "native-skia"))] 가드 안에 있어 기본 빌드 (native-skia 미활성) 에서는 메서드가 존재하지 않음. CI 의 cargo build --examples (기본 features) 가 본 example 빌드 시도 → "no method named render_page_png_native" 컴파일 에러 → CI fail. 해결: Cargo.toml 에 [[example]] 정의 추가 + required-features = ["native-skia"] 명시. 기본 빌드는 본 example 자동 skip. 검증: - cargo build --release --examples (기본 features): 통과 (example skip) - cargo build --release --examples --features native-skia: 통과 (example 빌드) - cargo test --lib --release 1134 passed (회귀 0)
PR #600 (closes #513, @oksure Hyunwoo Park) 1차 검토: - 본질 결함: Task #509 의 map_pua_bullet_char 매핑이 convert_pua_enclosed_numbers (composer) 의 CharOverlap 변환에 막혀 도달 못 함 - 본질 정정: composer.rs 에서 F02B1~F02C4 CharOverlap 제외 + paragraph_layout.rs 에 ⑩~⑳ 매핑 추가 (전체 20자 완성) - Copilot review 3개 응답 (aafe85a): ⑩~⑳ 테스트 + 주석 + 폭 계산 정합 - PR base skew (PR #571/#599 패턴) — UI MERGEABLE 표시지만 PR base diff 가 본 사이클 cherry-pick 모두 revert - 그러나 본질 commit 영역이 본 사이클 처리분과 0 중첩 (PR #592 의 SPUA-A 저영역 F0000~F00CF 와 다른 코드포인트 영역) → commit 단위 cherry-pick 가능 - 본 환경 임시 검증: 2 commits cherry-pick 충돌 0 + cargo test --lib --release 1134 passed (회귀 0) + clippy 0건 + PUA 테스트 12 passed 권장 처리: 옵션 A — commit 단위 cherry-pick (2 commits, 단순 머지 절대 금지) + 결정적 검증 + 광범위 sweep + 작업지시자 시각 판정.
…A SVG 출력 정정 — @oksure 2 commits + 시각 판정 ★ 통과) PR #600 (closes #513, @oksure Hyunwoo Park): - 본질 결함: Task #509 의 map_pua_bullet_char 매핑이 convert_pua_enclosed_numbers (composer) 의 CharOverlap 변환에 막혀 도달 못 함 - 본질 정정: composer.rs 에서 F02B1~F02C4 CharOverlap 제외 + paragraph_layout.rs 에 ⑩~⑳ 매핑 추가 (전체 20자 완성) - Copilot review 3개 응답 (aafe85a): ⑩~⑳ 테스트 + 주석 + 폭 계산 정합 PR base skew (PR #571/#599 패턴) — UI MERGEABLE 표시지만 PR base diff 가 본 사이클 cherry-pick 모두 revert. 그러나 본질 commit 영역이 본 사이클 처리분과 0 중첩 (PR #592 의 SPUA-A 저영역 F0000~F00CF 와 다른 코드포인트 영역 F02B1~F02C4) → commit 단위 cherry-pick 가능. cherry-pick 2 commits (충돌 0, author Hyunwoo Park 보존): - 34f8547 fix: Supplementary PUA-A (U+F02B1~F02C4) SVG 출력 정정 - 14f30e8 address review: ⑩~⑳ 테스트 추가 + 주석 갱신 + 폭 계산 정합 검증: - cargo test --lib --release 1134 passed (회귀 0) - cargo test --lib pua 12 passed (supplementary_pua_a_maps_circled_digits ⑩~⑳ GREEN) - svg_snapshot 6/6 / issue_546 1 / issue_554 12 / clippy 0 / build --release - 광범위 페이지네이션 sweep: 164 fixture / 1,614 페이지 / 회귀 0 - SVG 정량 (원문자 출현): pua-test 0→9 / mel-001 20→34 / kps-ai 32→34 / KTX 변경 없음 (PR 본문 100% 재현) 시각 판정 ★ 통과. 별개 영역 발견: pua-test U+F53A 옛한글 자모 시퀀스의 아래아 (U+119E ᆞ) 글리프 미렌더 — 별도 이슈 #615 등록 (옛한글 폰트 fallback 영역). closes #513.
버전 동기화 (4 패키지 모두 0.7.10): - Cargo.toml: 0.7.9 → 0.7.10 - rhwp-vscode/package.json: 0.7.9 → 0.7.10 - npm/editor/package.json: 0.7.9 → 0.7.10 - rhwp-studio/package.json: 0.7.9 → 0.7.10 CHANGELOG (한/영) 신규 항목 [0.7.10] — 2026-05-06: - v0.7.9 후속 patch 사이클 - 외부 기여자 7명 (PR 13건 cherry-pick) — @planet6897/Jaeook Ryu / @oksure / @seo-rii / @cskwork / @johndoekim / @nameofSEOKWONHONG / @jangster77 - 신규 기능: CLI 바이너리 릴리즈 (Issue #608/#612, @almet 요청) + PNG raster backend (PR #599, @seo-rii) + AI 파이프라인 / VLM 연동 도입 - 메인테이너 정정: Skia 폰트 영역 5개 (한글 fallback / font-path / char-fallback / VLM 옵션 / export-png CLI) - 인프라: CI 빌드 안정성 + 광범위 페이지네이션 회귀 sweep (164/1,614) - 후속 이슈 4건 + 잔여 PR 5건 (v0.7.11 후속 patch 영역) 자기검열 통과 (한컴 비교 / 최상급 / 공공기관 오인 표현 0).
v0.7.9 후속 patch 사이클 (5/4 ~ 5/6). ## 신규 기능 - **CLI 바이너리 릴리즈** (Issue #608/#612, @almet 의 요청) - 4 플랫폼 GitHub Release 자산 첨부 (Linux x86_64 / macOS x86_64+aarch64 / Windows x86_64) + SHA-256 체크섬 - **PNG raster backend** (PR #599, @seo-rii) — render P4 단계 - native Skia 기반 PageLayerTree → PNG export, native-skia feature gate - **AI 파이프라인 + VLM 연동 도입** (메인테이너 후속 정정): - --vlm-target claude (1568 longest edge / 1.15 MP, Claude Vision 정합) - --scale / --max-dimension (자동 scale 계산) - export-png CLI 명령 + 매뉴얼 (한글 + 영문 dual) - 한글 폰트 fallback chain + char 단위 fallback (공백 두부 정정) + --font-path 동적 로딩 ## 외부 PR cherry-pick (13 PR / 7 컨트리뷰터) - @planet6897 / Jaeook Ryu (협업): PR #587/#589/#561/#564/#570/#575/ #580/#584/#592/#593/#567 - @oksure (Hyunwoo Park): PR #600 (closes #513) - @seo-rii: PR #599 (refs #536) - @cskwork / @johndoekim / @nameofSEOKWONHONG / @jangster77 — 사이클 누적 ## 메인테이너 정정 Skia 폰트 영역 5개 정정 (한글 fallback / font-path / char-fallback / VLM 옵션 / export-png CLI). ## 인프라 - CI 빌드 안정성 (Cargo.toml [[example]] required-features) - 광범위 페이지네이션 회귀 sweep 도구 (164 fixture / 1,614 페이지 자동) ## 후속 이슈 - #613 (VLM 프리셋 확장) - #614 (DPI 메타데이터) - #615 (pua_oldhangul.rs U+F53A 한컴 정합) - #598 (rhwp-studio 각주 삭제, 외부 컨트리뷰터 공개) ## 잔여 PR (v0.7.11 후속 patch) PR #601, #602 (@oksure) / PR #607 (@dicebattle) / PR #609 (@jangster77, Task #604) / PR #611 (@kihyunnn). 상세: CHANGELOG.md (한글) / CHANGELOG_EN.md (영문).
PR #626 (Follow-up to #599, P5 단계 native Skia equation replay) 처리 완료 후속 영역: - mydocs/pr/archives/pr_626_review.md (1차 검토 + 옵션 분석 + cherry-pick simulation) - mydocs/pr/archives/pr_626_report.md (처리 결과 + native-skia 검증 + PNG 시각 판정 통과) - mydocs/orders/20260507.md PR #626 entry 추가 처리 결과 요약: - 옵션 A: 3 commits 단계별 cherry-pick (author seorii 보존) - devel commits: 067a18b (본질 +717 LOC equation_conv.rs) + dac1caa (docs P5) + 2f6918a (atop fix) - cargo test --lib (default) 1155 / cargo test --features native-skia skia --lib 22 (수식 replay 신규 테스트 포함) - clippy default + native-skia 0 / WASM 4,578,641 bytes (native-skia 영역 외) - 메인테이너 PNG 시각 판정 ★ 통과 (samples/exam_math.hwp 20 페이지 1.5MB) - PR #626 close + 한글 댓글 (연결 이슈 부재 — Follow-up to #599) 본 PR 의 정체성: - opt-in feature 영역 (native-skia) — 기본 빌드 영역 영향 부재 - PR #599 의 follow-up — P4 → P5 단계 진행 - DTP 엔진 (project_dtp_identity) native PNG 렌더링 영역 본질 영역 강화 본 사이클 (5/7) PR 처리 누적: 11건
변경 요약
이번 PR은 render P4 단계로,
PageLayerTree를 native Skia로 replay해서 PNG를 만들 수 있는 첫 raster backend를 추가합니다.P1에서
PageLayerTree경계를 만들고, P2/P3에서 Canvas layer path와 diff 테스트를 붙였고, 이번에는 그 IR을 native backend에서도 실제로 replay할 수 있는지 확인하는 단계입니다.주요 변경은 아래와 같습니다.
LayerRasterRenderer,RasterRenderOptions,RasterRenderOutput추가native-skiafeature 추가SkiaLayerRenderer추가DocumentCore::render_page_png_native(page)추가PageLayerTree기반 PNG encode 경로 추가이 PR의 Skia 경로는 아직 완성형 renderer라기보다는
PageLayerTree가 native raster backend까지 갈 수 있는지 검증하는 초기 backend입니다. 그래서 기본 SVG/Canvas 출력은 그대로 두고, native feature를 켰을 때만 PNG export API를 사용할 수 있게 했습니다.관련 이슈
refs #536
범위
이번 PR에 포함한 범위는 아래 정도입니다.
PageLayerTreereplay 기반 raster outputnative-skia비목표
아래는 일부러 이번 PR에 넣지 않았습니다.
특히 equation/raw-svg/form은 이번 PR에서는 placeholder/fallback replay 수준입니다. 실제 native replay는 후속 PR에서 따로 보는 게 맞습니다.
테스트
git diff --check upstream/devel...origin/render-p4cargo testcargo clippy -- -D warningscargo check --target wasm32-unknown-unknown --libcargo test --features native-skia skia --libSVG 샘플 내보내기와 웹 렌더링 확인은 이번 PR의 직접 범위가 아닙니다. P4는 native-only Skia PNG backend 추가이고, wasm 쪽은
cargo check --target wasm32-unknown-unknown --lib로 native Skia 의존성이 새지 않는지만 확인했습니다.스크린샷
없음.
이번 PR은 UI 변경이 아니라 native PNG raster backend 추가입니다. 대신 Skia 테스트에서 PNG decode, pixel sampling, clip, image crop/tile/effect, placeholder fallback, raster option guard를 확인합니다.