Skip to content

Task #860 + #864: EMF/WMF image 렌더 + HWP3 picture caption 정정#869

Closed
jangster77 wants to merge 8 commits into
edwardkim:develfrom
jangster77:local/task864
Closed

Task #860 + #864: EMF/WMF image 렌더 + HWP3 picture caption 정정#869
jangster77 wants to merge 8 commits into
edwardkim:develfrom
jangster77:local/task864

Conversation

@jangster77

Copy link
Copy Markdown
Collaborator

Summary

PR #863 (Task #860) 와 통합된 PR — Task #860 의 EMF/WMF image 렌더 정정에 더해, Task #864 의 WMF y 좌표 + HWP3 picture caption 위치 + inline image 중복 emit 을 모두 정정합니다.

Task #860: HWP3/HWP5/HWPX 의 EMF/WMF image 콘텐츠 렌더 정정 (closes #860)

  • BMP MIME 변환 (rsvg-convert 호환): EMF/WMF converter 의 BMP → PNG 변환
  • viewBox 자동 확장 (Stage D)

Task #864: WMF y 좌표 + HWP3 picture caption + 중복 emit 정정 (closes #864)

본질 1 (WMF): 5개 image record handler (bit_blt, dib_bit_blt, dib_stretch_blt, stretch_blt, stretch_device_independent_bitmap) 의 image x/y 를 point_s_to_absolute_point 로 변환. text/polygon 과 동일 device 공간 정합. as_view_box(0, 0, ext_x, ext_y) 로 revert (Task #860 Stage D 미봉책 정정).

본질 2 (HWP3 caption): inline (TAC) picture caption 의 y_start 를 image_bottom (pic_y + max(baseline, pic_h)) 에 정합. paragraph_layout 의 baseline-aligned image 와 정합.

본질 3 (중복 emit): paragraph_layout 의 inline TAC picture emit 시 set_inline_shape_position 호출 추가. layout.rsalready_registered 체크 통과시켜 중복 emit (top-aligned + baseline-aligned 동시 출력) 방지.

추가: caption 렌더 후 result_y 를 caption bottom 까지 진행하여 다음 paragraph 와의 겹침 방지. dump 출력에 picture caption 정보 표시.

Test plan

  • cargo build --release
  • cargo test --release --lib (1230 passed, 회귀 0)
  • cargo clippy --release --lib (경고 0)
  • hwp3-sample14 page 2: BMP 위, WMF 내부 캡션 아래 (한컴 PDF 정합) ✓
  • hwp3-sample14 page 3: "Cut&Paste 할 영역" caption 정상 표시 + body 자연 간격 ✓
  • hwp3-sample14 page 4: "Visual Block을 이용한 대소문자 변경" caption 정상 + body 자연 간격 ✓
  • hwp3-sample14 전체 11 페이지 회귀 0
  • hwp3-sample14-hwp5 동등 ✓
  • hwp3-sample4 (다른 WMF 사용 sample) 회귀 0

CLAUDE.md 규칙 준수

HWP3 전용 분기 0건. 모든 변경은 generic 모듈 (WMF format converter, 공통 renderer) 로 모든 포맷 (HWP3/HWP5/HWPX) 에 정합 동작.

Closes

🤖 Generated with Claude Code

jangster77 and others added 7 commits May 13, 2026 01:15
…dwardkim#860

본질: HWP3 sample14 (및 HWP5/HWPX 변환본) 의 그림 (bin_id=2, 149.9×41.9mm
TAC) 내부 콘텐츠 누락. 한컴 한글 2022 PDF (권위) 와 시각 다름.

2 layers 본질 진단 (Stage A/B/C):

1차 본질 — BMP MIME 미지원:
- rhwp 가 EMF/WMF 의 inner BMP image 를 `data:image/bmp;base64,...` 로 SVG
  embed. rsvg-convert / 브라우저 가 BMP MIME 미지원 → image 누락.
- BMP 데이터 자체는 정상 (sips 직접 변환 시 terminal screenshot 표시).

2차 본질 — WMF SVG converter 의 viewBox 부족:
- WMF binary 의 SetWindowExt (4231x1189) 가 actual element bbox 보다 작음
  (image y=1536 + h=768 = 2304 > viewBox h=1189) → image 가 viewBox 밖 →
  rsvg-convert 가 잘라냄.
- viewBox 를 1189 → 3000 으로 확장 시 image 정상 표시 (검증 완료).

정정:
1. src/emf/converter/player.rs:368 dib_to_bmp_data_url — BMP 데이터를 PNG 로
   재인코딩 후 data:image/png URI 사용 (svg.rs:1118 / shape_layout.rs:1063
   와 동일 정책). BMP decode 실패 시 fallback 으로 BMP URI 유지.
2. src/wmf/converter/svg/util.rs:20 Bitmap::as_data_url — 동일 BMP → PNG
   변환 적용.
3. src/wmf/converter/svg/mod.rs:68-90 SVGPlayer::generate() — viewBox 자동
   확장. element 들의 max(x+width, y+height) 까지 확장하여 actual bbox
   cover. helper: element_max_x, element_max_y, parse_attr_i32.
4. src/emf/tests.rs:712 test assert update — data:image/png 또는 BMP URI
   둘 다 허용 (graceful degradation).

검증:
- cargo test --release --lib: 1230 passed, 0 failed (회귀 0)
- HWP3 sample14 page 2 시각: 박스 안 "If you leave me now / You'll take
  away the biggest part of me / Ooh-ooh, baby ase pl[c]don't go" 등 콘텐츠
  정상 표시 (한컴 PDF 정합)
- HWP5/HWPX 변환본 동일 정합
- hwp3-sample13, exam_eng 회귀 없음 (페이지 수 동일)

산출 보고서:
- mydocs/working/task_m100_860.md (종합)
- mydocs/working/task_m100_860_stage_a.md (본질 진단)
- mydocs/working/task_m100_860_stage_b.md (정정 후보 평가)
- mydocs/working/task_m100_860_stage_c.md (구현 + 추가 발견)
- mydocs/plans/task_m100_860.md, _impl.md (계획서)

샘플 추가: samples/hwp3-sample13(-hwp5).{hwp,hwpx}, hwp3-sample14(-hwp5).{hwp,hwpx},
권위 PDF: pdf/hwp3-sample{13,14}-hwp5-2022.pdf

잔여 결함 (별도 issue 등록 예정):
- paragraph 순서 차이 (그림 + 캡션 paragraph 의 page boundary 처리) —
  본 task 의 BMP 콘텐츠 결함과 독립적인 layout/pagination 결함

closes edwardkim#860

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…amework

선행: Task edwardkim#860 Stage A-C (commit 4908ab0) 의 BMP image 콘텐츠 fix.
잔여 결함 (그림 paragraph 의 element 순서) 본질 진단 + 부분 정정.

본질 진단 결과:
- WMF SetWindowOrg: (329, 1536), Ext: (4231, 1189) 모두 positive (top-down)
- Placeable BoundingBox: (329, 1536) ~ (4560, 2725)
- element y 좌표: rect 1008, text 1205, image 1536
- 결함: rect/text y < origin_y (1536) → window 위쪽 밖 위치
  (rhwp 는 캡션 outline 위, BMP 박스 아래 / 한컴 PDF 는 박스 위, 캡션 아래)

가설 검증:
- H4 (그림 control 내 element 순서) ✓ 확정
- H5 (SetWindowExt y < 0 Cartesian) ✗ — sample14 는 positive
- H6 (y-flip framework) — 도입 (현재 sample 미적용, 다른 sample 사용 예정)

적용한 정정:

Fix 1 — Window::as_view_box() viewBox origin 적용:
- 종전 (0, 0, x, y) → (origin_x, origin_y, x, y)
- SetWindowOrg 의 origin 을 viewBox 시작점으로 사용
- WMF binary 의 좌표계 정합

Fix 2 — viewBox 양방향 자동 확장 (SVGPlayer::generate):
- 종전: max(x+w, y+h) 까지 우/하 확장
- 추가: min(x, y) 까지 좌/상 확장
- element 가 viewBox 위쪽 밖에 있는 경우 (sample14 의 rect/text) 정상 표시
- helper: element_min_x, element_min_y, parse_attr_i32

Fix 3 — y-flip framework (도입, 현재 미적용):
- Window::ext() 에서 SetWindowExt y < 0 (Cartesian, bottom-up) 감지
- y_inverted flag → generate() 가 <g transform="translate(0,vb_h) scale(1,-1)"> wrap
- 본 sample14 는 y_inverted=false (positive y) — 다른 Cartesian sample 에서 작동 예정

검증:
- cargo test --release --lib: 1230 passed, 0 failed (회귀 0)
- HWP3 sample13 / exam_eng: WMF 미사용 (회귀 영향 없음)
- HWP3 sample14: BMP image 콘텐츠 표시 + viewBox 정합

잔여 결함 (별도 task 권장):
- element y 좌표 순서 자체가 한컴과 반대
  (rhwp: rect/text 위 + image 아래 / 한컴: image 위 + rect/text 아래)
- WMF binary 의 element 가 BoundingBox 밖에 위치하는 비정상 또는
  좌표 처리 본질 차이. WMF spec 정밀 분석 + 좌표계 재설계 필요
- 본 task scope 보다 큼 → 별도 deep task

산출 보고서:
- mydocs/working/task_m100_860_v2.md (Stage D 종합)
- mydocs/working/task_m100_860_stage_d_a.md (Stage D 진단)
- mydocs/plans/task_m100_860_v2.md, _impl.md (Stage D 계획서)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
본질 1 (WMF): 5개 image record handler (bit_blt, dib_bit_blt, dib_stretch_blt,
stretch_blt, stretch_device_independent_bitmap) 의 image x/y 를
point_s_to_absolute_point 로 변환. text/polygon 과 동일 device 공간 정합.
as_view_box 를 (0, 0, ext_x, ext_y) 로 revert (Task edwardkim#860 Stage D 미봉책 정정).
element_max_y 에 text font-size 기반 viewBox 자동 확장 추가.

본질 2 (HWP3 caption): inline (TAC) picture caption 의 y_start 를 image_bottom
(pic_y + max(baseline, pic_h)) 에 정합. paragraph_layout 의 baseline-aligned
image 와 정합 (HWP3 sample14 page 3 "Cut&Paste 할 영역", page 4 "Visual Block
을 이용한 대소문자 변경" caption 가 image 에 가려지던 결함).

본질 3 (중복 emit): paragraph_layout 의 inline TAC picture emit 시
set_inline_shape_position 호출 추가. layout.rs 의 already_registered 체크
통과시켜 중복 emit (top-aligned + baseline-aligned 동시 출력) 방지.

추가: caption 렌더 후 result_y 를 caption bottom 까지 진행하여 다음
paragraph 와의 겹침 방지. dump 출력에 picture caption 정보 표시.

검증: cargo test 1230 passed (회귀 0), clippy 경고 0.
hwp3-sample14 page 2/3/4 모두 한컴 PDF 시각 정합.

closes edwardkim#864
edwardkim pushed a commit that referenced this pull request May 14, 2026
closes #864)

PR #869 (@jangster77) GitHub diff 기반 cherry-pick.
mydocs 거버넌스 산출물 제외 (PR #629 패턴 정합).

Task #860 — BMP MIME 변환 (PNG 재인코딩) + viewBox 자동 확장
Task #864 — WMF image x/y point_s_to_absolute_point 변환
         + HWP3 inline picture caption y_start 정합
         + set_inline_shape_position 추가로 중복 emit 방지
         + caption bottom까지 result_y 진행 (겹침 방지)
         + dump에 picture caption 정보 표시

fixture: hwp3-sample13/14 HWP3/HWP5/HWPX + PDF 권위 자료

검증:
- cargo test --release --lib: 1246 passed (회귀 0)
- cargo clippy: 경고 0
- SVG page 2/3/4 + 웹 에디터 시각 판정 ★ 통과

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@edwardkim

Copy link
Copy Markdown
Owner

검토 + cherry-pick 머지 완료. 감사합니다.

처리 결과

재검증

검증 결과
cargo test --release --lib 1246 passed (회귀 0)
cargo clippy 경고 0
SVG (hwp3-sample14 page 2/3/4) 시각 판정 ★ 통과
웹 에디터 시각 판정 ★ 통과

BMP→PNG 재인코딩 + WMF 좌표계 정합 + caption 위치 + 중복 emit 방지까지 다층 결함을 체계적으로 정리했습니다. 수고하셨습니다.

@edwardkim edwardkim closed this May 14, 2026
edwardkim pushed a commit that referenced this pull request May 14, 2026
PR #875 (@jangster77) GitHub diff 기반 cherry-pick (Task #873 incremental만).
mydocs 거버넌스 산출물 + PR #869 중복 영역 제외.

본질 1 (HWP5): BinDataType::Link abs_path → Picture.external_path 전달
  parser/mod.rs populate_link_image_paths 후속 함수 추가
본질 2 (HWPX): content.hpf isEmbeded attribute 파싱 + image/* 수집
  parser/hwpx/content.rs PackageItem.is_embedded + parser/hwpx/mod.rs Link 분기

검증:
- cargo test --release --lib: 1247 passed (+1 신규, 회귀 0)
- 웹 에디터 동작 판정 ★ 통과

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants