Task #195 — OLE/Chart 네이티브 렌더링 (EMF + OOXML 차트 + HWPX + 네이티브 이미지)#221
Merged
edwardkim merged 18 commits intoApr 20, 2026
Conversation
- 수행계획서/구현계획서 (차트+OLE 프리뷰, 5단계 분할) - CHART_DATA 구조/ChartShape IR 문서 - SHAPE_COMPONENT_OLE 구조/OleShape IR 문서 - BinData 스트림 압축 실측 기록 (1.hwp BIN0001/BIN0002 비표준 매직) - 단계1 완료보고서
- ShapeObject enum에 Chart(Box<ChartShape>), Ole(Box<OleShape>) 추가 - ChartType/LegendPosition/Axis/Legend/DataSeries/OlePreview 등 타입 신규 - raw_chart_data/raw_tag_data 필드로 라운드트립 보존 - 8개 매치 사이트(렌더러/직렬화/object_ops/dump/tests) Chart/Ole arm 추가 - 렌더링은 placeholder Rectangle (단계 4에서 교체) - cargo test: 875 passed 0 failed
- HWPTAG_SHAPE_COMPONENT_OLE를 shape_tag_id로 수집 - HWPTAG_CHART_DATA 존재 시 차트 우선 분류 - parse_ole_shape: extent/flags/drawing_aspect/bin_data_id 파싱 + raw 보존 - 미지 태그 Rectangle 폴백 경로 유지 (이제 차트/OLE는 여기로 안 옴) - dump: 하드코딩 "도형" → shape_name() 사용 - 1.hwp 2개 OLE 컨트롤 정상 분류 확인 - 단위 테스트 3건 추가 (총 878 passed)
- Chart: 연한 파란 (#E8F0FE) + #4A90E2 대시 테두리 - Ole: 연한 회색 (#F0F0F0) + #909090 대시 테두리 - drawing의 fill/stroke가 이미 있으면 유지 (is_none일 때만 오버라이드) - 1.hwp export-svg 확인: 2개 OLE placeholder 정상 렌더
- 기존 samples/ 회귀 테스트 (draw-group/aift/biz_plan): 크래시 없음 - 전체 테스트 878+13 passed - 오늘할일(20260419) edwardkim#195 완료 항목 추가, 후속 이슈 2건 제안 - 최종 보고서 작성 자체 제작 samples/chart-basic.hwp은 한컴오피스 authoring 환경 부재로 분리 이슈로 이월.
- RenderNodeType::Placeholder variant 신규 - svg.rs draw_rect_with_gradient: stroke_dash 누락 수정 (기존 버그) - Chart: '차트 (Chart)' 라벨, 연한 파란 배경 - Ole: 'OLE 개체 (BinData #NNN)' 라벨, 연한 회색 배경 - 중앙 정렬 텍스트, 폰트 크기는 박스 크기 기준 clamp(12, 28) - 1.hwp 페이지 3/4 육안 검증: 라벨 정상 렌더 - cargo test: 878 passed 0 failed
작업지시자 요청: placeholder를 넘어 실제 OLE 데이터 렌더링까지 확장 - 단계 6: BinData 스트림 해제 인프라 (zlib raw deflate + DocInfo 플래그) - 단계 7: 내부 CFB 파싱 (OlePres000/OOXMLChartContents/Contents) - 단계 8: OOXML 차트 네이티브 SVG 렌더 + EMF 폴백 1.hwp 실측 기반: - BIN0001.OLE: 30KB → 해제 후 384KB CFB - 내부: EMF 프리뷰 + OOXML barChart XML 모두 존재 - 1차 경로는 OOXML(벡터 품질, 순수 Rust), 폴백은 EMF 파일 참조
단계 6 — BinData 해제 인프라: - load_bin_data_content: Storage(OLE) 타입도 로드 (기존은 Embedding만) - OLE 해제 후 4-byte size prefix 자동 스킵하여 CFB 매직부터 노출 단계 7 — 내부 CFB 파싱: - src/parser/ole_container.rs 신규 - cfb crate로 중첩 OLE 컨테이너 파싱 - \x02OlePres000 / OOXMLChartContents / Contents 스트림 추출 - OLE Presentation Stream 헤더 스킵 후 EMF 바이트 반환 단계 8 — OOXML 차트 렌더: - src/ooxml_chart/ 신규 모듈 (parser + renderer) - quick-xml으로 DrawingML 파싱 → OoxmlChart 데이터 모델 - 지원: barChart(col/bar) / lineChart / pieChart - RenderNodeType::RawSvg variant 신규 (사전 생성 SVG 조각 삽입) - shape_layout.rs Ole arm: OOXML 성공 시 실제 차트, 실패 시 placeholder 폴백 - parse_ole_shape의 bin_data_id 오프셋 수정 (1.hwp 실측 기반) 1.hwp 검증: - 페이지 3: 월별 기부 금액/건수 막대 차트 (2 시리즈 × 12) - 페이지 4: 시간대별 기부 건수 막대 차트 - 이전 placeholder 텍스트 대신 실제 데이터 기반 벡터 차트 cargo test: 890 passed 0 failed (기존 878 + 신규 12)
## 변경 사항 ### ooxml_chart (콤보 차트 + 이중 Y축) - OoxmlSeries에 series_type/axis_group/axis_ids/format_code 필드 추가 - 파서: barChart/lineChart 공존 인식, valAx axPos로 primary/secondary 축 매핑 - 시리즈 색상 추출: spPr의 srgbClr (직접 RGB) + schemeClr (accent1~6 매핑) - 숫자 포맷: c:formatCode 파싱, 천 단위 콤마 지원 - 렌더러: 콤보 렌더, 이중 Y축, 라인 데이터 포인트 마커, nice-number 눈금 ### HWPX 차트 파싱 (신규) - parse_hwpx: Chart/chartN.xml을 BinDataContent에 주입 (id=60000+N, extension=ooxml_chart) - section.rs: hp:switch/hp:case/hp:chart 엘리먼트 핸들러 추가 - hp:switch 내부 OOXML 차트 우선, 없으면 hp:ole fallback - 공통 shape 속성(sz, pos, outMargin) 파싱 헬퍼 추가 ### 렌더러 연결 - find_bin_data: 1-indexed 순번 실패 시 id 필드로 직접 검색 fallback - shape_layout Ole arm: extension=ooxml_chart면 CFB 파싱 건너뛰고 직접 렌더
## 변경 사항
### ole_container.rs
- NativeImageKind enum (Bmp/Png/Jpeg/Gif) 추가, mime() 유틸 제공
- OleContainer.native_image: Option<(NativeImageKind, Vec<u8>)> 필드 추가
- 파싱 경로:
1. \x01Ole10Native 스트림 인식: 4바이트 LE 길이 프리픽스 이후 매직 바이트로 포맷 판별
2. EMF/OOXMLChart/Ole10Native 모두 부재 시 OlePres000에서 DIB 추출 폴백
BITMAPINFOHEADER(biSize=40) 스캔 → 14바이트 BMP FILEHEADER 합성 → 표준 BMP 재포장
- detect_native_image(), extract_dib_as_bmp() 유틸 추가
### shape_layout.rs (Ole arm)
- OLE 렌더 폴백 순서 확장: OOXML 차트 → EMF → native_image → placeholder
- native_image 렌더: base64 data URI를 xlink:href + href 이중 속성으로 <image> 요소 생성
## 동기
bitmap.hwp처럼 OLE 컨테이너에 BMP만 임베딩된 경우 EMF 프리뷰 부재로
'OLE 개체 (BinData #1)' placeholder만 표시되던 문제 해결. 손글씨 드로잉,
스캔 이미지, OLE-embedded 스크린샷 등이 실제 이미지로 렌더링됨.
## 검증
- bitmap.hwp → 손글씨 선 그림 정상 렌더링
- 차트1.hwp 회귀 없음 (2차트 정상)
- cargo test --lib ole_container 통과 (4/4)
This was referenced Apr 20, 2026
Closed
edwardkim
added a commit
that referenced
this pull request
Apr 20, 2026
PR #181 (by @seunghan91) 가 2026-04-17 기준으로 작성된 후 다음 두 PR 이 devel 에 머지되어 SVG 출력이 변경됨: - #213 (cherry-picked by @jskang): HWPX char offsets interleaved 보정 - #221 (by @planet6897): OLE/Chart/EMF 네이티브 렌더링 + HWPX 차트 파서 두 fix 가 form-002 렌더링에 반영되어 원본 golden 과 diff 발생. `UPDATE_GOLDEN=1 cargo test --test svg_snapshot` 로 재생성 후 결정성 확인 완료. Verification: - cargo test --test svg_snapshot → 2 passed (form_002_page_0 + render_is_deterministic_within_process) - 재실행 back-to-back 결정성 유지 Refs #181 · #173 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim
added a commit
that referenced
this pull request
Apr 20, 2026
…est 실패 수정) PR #221 Stage 3에서 추가된 parse_ole_shape 의 doc comment 가 언어 지시자 없는 \`\`\` 블록으로 되어있어, rustdoc 이 Rust 코드로 해석 시도 → \"01 00 00 00\" + 화살표(←, U+2190) 등이 Rust 토큰으로 파싱 실패. 수정: \`\`\` → \`\`\`text 로 변경하여 doctest 대상에서 제외. 검증: - cargo test --doc: 컴파일 에러 0, 0 passed / 0 failed - cargo test --lib: 935 passed, 0 failed (기존 그린 유지) CI 실패 로그: run #24669204138 (2026-04-20T13:30) error: unknown start of token: \\u{2190} --> src/parser/control/shape.rs:295:32 Refs #221 #195 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim
added a commit
that referenced
this pull request
Apr 20, 2026
CI가 cargo clippy -- -D warnings 로 돌아 warning 을 error 처리. PR #221 신규 코드에서 3건 위반: 1. src/parser/hwpx/section.rs:2939 — unused-parens ole.bin_data_id = (60000u32 + chart_num as u32); → 괄호 제거 2. src/emf/converter/device_context.rs:76 — doc-lazy-continuation doc 리스트 아래 설명 단락 앞에 빈 주석줄 추가 3. src/ooxml_chart/renderer.rs:55 — manual-is-multiple-of (len - i) % 3 == 0 → (len - i).is_multiple_of(3) 검증: - cargo clippy -- -D warnings: 0 errors, 0 warnings - cargo test --lib: 935 passed CI 실패 로그: run #24670427894 Refs #221 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim
added a commit
that referenced
this pull request
Apr 20, 2026
2026-04-20~21 사이클 정리: PR 처리 9건: - admin merge 5: #209 #214 #215 #221 #224 - cherry-pick + close 2: #213 (+중복 #210 close), #181 (+golden 재생성) - dependabot close 2: #211 #212 (devel 수동 bump + target-branch=devel 설정) - 보류 1: #165 skia (별도 사이클) 이슈 close 7: #173 #195 #202 #205 #207 #210 #222 신규 이슈 등록 1: #204 (표 Undo/Redo) Chrome Web Store / Edge Add-ons v0.2.1 심사 통과 (2026-04-21). local/task205 폐기: PR #209+#214 가 중복 처리하여 잔여 고유 기여 분리 곤란. 기여자 7명 감사 기록. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim
added a commit
that referenced
this pull request
Apr 21, 2026
한글판 README.md 와 영문판 README_EN.md 의 섹션 구조·내용을 1:1 일치시킴. 주요 변경: - Roadmap + Milestones 섹션을 상단(로드맵/이정표 위치) 으로 이동 - v0.5.0 ~ v0.7.x 이정표에 v0.2.1 사이클 전체 반영 (Chrome/Edge 심사 통과, PR #213/#215/#221/#169/#209/#214/#224/#181) - rhwp-firefox (v0.1.1 AMO 준비) + rhwp-safari (v0.2.1) 섹션 추가 - 기여자 감사 목록 확장: @seo-rii, @planet6897, @yl-star7 추가 (9명) - Features: OLE/Chart/EMF native rendering 항목 추가 (#221) - Project Structure: src/emf/, src/ooxml_chart/, rhwp-firefox/, rhwp-shared/ 반영 - Trademark 섹션 신규 (한글판 동일 위치) - AI 페어 프로그래밍 섹션: Git Workflow / Task Workflow / Debugging Protocol / Documentation Rules 완전 반영 - 로드맵 링크를 mydocs/eng/report/rhwp-milestone.md 로 보정 - 테스트 수치 783 → 935 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim
added a commit
that referenced
this pull request
Apr 22, 2026
한글판 README.md 와 영문판 README_EN.md 의 섹션 구조·내용을 1:1 일치시킴. 주요 변경: - Roadmap + Milestones 섹션을 상단(로드맵/이정표 위치) 으로 이동 - v0.5.0 ~ v0.7.x 이정표에 v0.2.1 사이클 전체 반영 (Chrome/Edge 심사 통과, PR #213/#215/#221/#169/#209/#214/#224/#181) - rhwp-firefox (v0.1.1 AMO 준비) + rhwp-safari (v0.2.1) 섹션 추가 - 기여자 감사 목록 확장: @seo-rii, @planet6897, @yl-star7 추가 (9명) - Features: OLE/Chart/EMF native rendering 항목 추가 (#221) - Project Structure: src/emf/, src/ooxml_chart/, rhwp-firefox/, rhwp-shared/ 반영 - Trademark 섹션 신규 (한글판 동일 위치) - AI 페어 프로그래밍 섹션: Git Workflow / Task Workflow / Debugging Protocol / Documentation Rules 완전 반영 - 로드맵 링크를 mydocs/eng/report/rhwp-milestone.md 로 보정 - 테스트 수치 783 → 935 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim
added a commit
that referenced
this pull request
Apr 23, 2026
…ot 반영) 피드백 mydocs/feedback/manual_currency_audit.md 결정 반영. 최근 사이클의 주요 변경을 매뉴얼에 동기화하고, PR 처리 절차 매뉴얼을 신설. [A] publish_guide.md - 버전 예시 0.7.0 → 0.7.3 (현재 릴리즈 기준) - 커맨드 예시 갱신 (git tag v0.7.3 등) - 테스트 수치 783 → 941 - 신규 섹션 "브라우저 확장 버전 정책 (라이브러리와 이원화)" — v0.2.x 정책 명문화 [B] chrome_edge_extension_build_deploy.md → 통합 확장 매뉴얼로 확장 - 제목: "브라우저 확장 빌드 및 배포 매뉴얼 (Chrome/Edge/Firefox/Safari)" - 빌드 크기 실측치 갱신 (WASM 3.9MB · 전체 23MB) - 테스트 페이지에 06-security.html 추가 - 4.4 절 Firefox (AMO 제출 절차) + 4.5 절 Safari (macOS 전용 빌드) 신규 [C] browser_extension_dev_guide.md - 제목: Safari/Chrome/Edge → Safari/Chrome/Edge/Firefox - Service Worker vs Background Scripts 표에 Firefox 열 추가 - 9절 신규 "chrome.* vs browser.* 네임스페이스 차이" - 10절 신규 "rhwp-shared/ 공통 모듈 + 심볼릭 링크 + dereference 빌드 패턴" (PR #214) - 11절 신규 "Chrome onDeterminingFilename vs Firefox onCreated+onChanged" [D] hyper_waterfall.md - 783+ 테스트 → 941+ 테스트 - "1인 개발" → "1인 메인테이너 + Claude Code AI + 외부 기여자 9명 (v0.2.1 기준)" - "v0.6.0 릴리즈" → "v0.5.0 공개 릴리즈 (뼈대 완성 지점)" [E] e2e_verification_guide.md - 신규 섹션 "SVG 회귀 검증 (Rust 유닛 테스트 기반)" — PR #181 하네스 - UPDATE_GOLDEN=1 사용법, 결정성 재확인 절차 - 경고: 렌더 영향 PR 머지 후 golden 재생성 필수 (PR #221 / #251 2회 재현) - 신규 섹션 "향후 작업 — 한컴 PDF 기준 Visual Diff 하네스" — 이슈 #253 [F] onboarding_guide.md - E2E 모드 설명 환경 일반화 (Windows Chrome → 로컬/컨테이너 헤드리스 · 호스트 Chrome/Chromium) [G.2] 신규 mydocs/manual/pr_review_workflow.md - PR 리뷰 · 통합 워크플로우 표준화 - 리뷰 문서 2종 (review + impl) 작성 절차 - 로컬 사전 검증 (빌드/테스트/Clippy/doctest/svg_snapshot) - Admin merge 후 필수 후속 (이슈 close · 감사 코멘트 · devel sync · golden 재생성 · archives 이동) - 재작업 요청 패턴 (PR #234 → #251 사례) - 예외 케이스 (dependabot · 오래된 base · 대형 PR) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim
added a commit
that referenced
this pull request
Apr 23, 2026
…ot 반영) 피드백 mydocs/feedback/manual_currency_audit.md 결정 반영. 최근 사이클의 주요 변경을 매뉴얼에 동기화하고, PR 처리 절차 매뉴얼을 신설. [A] publish_guide.md - 버전 예시 0.7.0 → 0.7.3 (현재 릴리즈 기준) - 커맨드 예시 갱신 (git tag v0.7.3 등) - 테스트 수치 783 → 941 - 신규 섹션 "브라우저 확장 버전 정책 (라이브러리와 이원화)" — v0.2.x 정책 명문화 [B] chrome_edge_extension_build_deploy.md → 통합 확장 매뉴얼로 확장 - 제목: "브라우저 확장 빌드 및 배포 매뉴얼 (Chrome/Edge/Firefox/Safari)" - 빌드 크기 실측치 갱신 (WASM 3.9MB · 전체 23MB) - 테스트 페이지에 06-security.html 추가 - 4.4 절 Firefox (AMO 제출 절차) + 4.5 절 Safari (macOS 전용 빌드) 신규 [C] browser_extension_dev_guide.md - 제목: Safari/Chrome/Edge → Safari/Chrome/Edge/Firefox - Service Worker vs Background Scripts 표에 Firefox 열 추가 - 9절 신규 "chrome.* vs browser.* 네임스페이스 차이" - 10절 신규 "rhwp-shared/ 공통 모듈 + 심볼릭 링크 + dereference 빌드 패턴" (PR #214) - 11절 신규 "Chrome onDeterminingFilename vs Firefox onCreated+onChanged" [D] hyper_waterfall.md - 783+ 테스트 → 941+ 테스트 - "1인 개발" → "1인 메인테이너 + Claude Code AI + 외부 기여자 9명 (v0.2.1 기준)" - "v0.6.0 릴리즈" → "v0.5.0 공개 릴리즈 (뼈대 완성 지점)" [E] e2e_verification_guide.md - 신규 섹션 "SVG 회귀 검증 (Rust 유닛 테스트 기반)" — PR #181 하네스 - UPDATE_GOLDEN=1 사용법, 결정성 재확인 절차 - 경고: 렌더 영향 PR 머지 후 golden 재생성 필수 (PR #221 / #251 2회 재현) - 신규 섹션 "향후 작업 — 한컴 PDF 기준 Visual Diff 하네스" — 이슈 #253 [F] onboarding_guide.md - E2E 모드 설명 환경 일반화 (Windows Chrome → 로컬/컨테이너 헤드리스 · 호스트 Chrome/Chromium) [G.2] 신규 mydocs/manual/pr_review_workflow.md - PR 리뷰 · 통합 워크플로우 표준화 - 리뷰 문서 2종 (review + impl) 작성 절차 - 로컬 사전 검증 (빌드/테스트/Clippy/doctest/svg_snapshot) - Admin merge 후 필수 후속 (이슈 close · 감사 코멘트 · devel sync · golden 재생성 · archives 이동) - 재작업 요청 패턴 (PR #234 → #251 사례) - 예외 케이스 (dependabot · 오래된 base · 대형 PR) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
요약
OLE 개체를 단순 placeholder로 표시하던 문제를 해결하여 차트·임베딩 이미지·EMF 메타파일을 네이티브 SVG로 렌더링한다. HWP 바이너리 / HWPX 양쪽 포맷을 지원.
주요 변경
모델
파서
OOXML 차트 (src/ooxml_chart/)
EMF 네이티브 변환기 (src/emf/)
렌더러 (src/renderer/)
검증
sample.zip
│ 파일 │ 포맷 │ Before │ After │
│ 차트1.hwp │ HWP │ 단일 파란 바 │ 녹색 바 + 파란 라인 + 이중축 + 콤마 │
│ 차트.hwpx │ HWPX │ 공백 페이지 │ 차트1.hwp와 동일 렌더 │
│ bitmap.hwp │ HWP (BMP) │ "OLE 개체" placeholder │ 손글씨 드로잉 정상 렌더 │
범위 밖