Skip to content

Task #430: 그림 자동 크롭(FitToSize+crop) 공식 교정 — exam_kor 헤더 "국어 영역" 정상 표시#434

Closed
planet6897 wants to merge 5 commits into
edwardkim:develfrom
planet6897:local/task430
Closed

Task #430: 그림 자동 크롭(FitToSize+crop) 공식 교정 — exam_kor 헤더 "국어 영역" 정상 표시#434
planet6897 wants to merge 5 commits into
edwardkim:develfrom
planet6897:local/task430

Conversation

@planet6897

Copy link
Copy Markdown
Contributor

배경

samples/exam_kor.hwp 1쪽 상단 가운데 헤더 이미지가 SVG 출력에서 국어 영역(A 형) 으로 표시(원본 전체가 강제 스트레치되어 가로 폭 압축). 한컴 PDF는 국어 영역 만 표시 — PDF가 정답.

단계 표시 텍스트 이미지 폭(px)
수정 전 (rhwp) 국어 영역(A 형) 2320 (원본 전체)
수정 후 (rhwp) 국어 영역 1364.88 (좌측 58.8%)
한컴 PDF 국어 영역 1137 (PDF 비트맵)

근본 원인

HWP 그림 컨트롤(Picture)의 crop 필드는 정상 파싱돼 ImageNode.crop 까지 전달되고 있었으나, SVG/Canvas 렌더러의 스케일 변환 공식이 잘못돼 crop이 사실상 무력화되고 있었다.

잘못된 공식 (수정 전)

let scale_x = cr as f64 / img_w;          // 스케일을 crop 우경계로부터 추정
let src_w  = (cr - cl) as f64 / scale_x;  // 결과: cr/(cr/img_w) = img_w (항상 전체 폭)

cr(crop 우경계 HWPUNIT) 을 마치 원본 이미지 우경계인 양 다뤘다. 결과적으로 어떤 crop 값이 와도 src 영역이 항상 이미지 전체와 일치해 crop 이 무효.

올바른 공식 (수정 후)

let scale_x = original_width_hu  / img_w_px;   // 진짜 HU/px 스케일
let scale_y = original_height_hu / img_h_px;
let src_x = cl as f64 / scale_x;
let src_y = ct as f64 / scale_y;
let src_w = (cr - cl) as f64 / scale_x;
let src_h = (cb - ct) as f64 / scale_y;

본 이슈 케이스 입력값:

  • original_size_hu = (174000, 26580), img_px = (2320, 354)
  • crop = (0, 0, 102366, 26580)
  • scale = (75, 75.08) HU/px
  • src = (0, 0, 1364.88, 354)

이 src 영역만 SVG <svg viewBox=...> 로 노출 → "국어 영역" 만 보임.

변경

1. 모델 — ImageNode.original_size_hu 필드 추가

파일 변경
src/renderer/render_tree.rs ImageNodeoriginal_size_hu: Option<(u32, u32)> 필드 추가. pic.shape_attr.{original_width, original_height} 와 동일 단위(HWPUNIT)

기존에는 crop 만으로 src 좌표를 추정하려 했기 때문에 공식이 깨졌다. 원본 크기(HU)가 명시적으로 노드에 실리면 HU → px 스케일을 직접 계산할 수 있다.

2. 레이아웃 — ImageNode 채우기

파일:사이트 경로 변경
src/renderer/layout/picture_footnote.rs layout_picture 표 셀 그림 (본 케이스) original_size_hu 채움
src/renderer/layout/picture_footnote.rs layout_body_picture body picture 동일
src/renderer/layout.rs (~2614) TAC + 텍스트 없는 문단 동일
src/renderer/layout/table_cell_content.rs:635 셀 텍스트 안 picture None 명시 (컴파일 호환)

3. 렌더러 — 헬퍼 추출 + 공식 교정

파일 변경
src/renderer/svg.rs 헬퍼 compute_image_crop_src(crop_hu, original_size_hu, img_w_px, img_h_px) -> (sx, sy, sw, sh) 추가(pub(crate)). render_image_nodeFitToSize+crop 분기가 헬퍼 호출. original_size_huNone 인 폴백 동작 보존
src/renderer/web_canvas.rs draw_image_with_fill_mode 시그니처에 original_size_hu 추가 + 동일 헬퍼 호출. SVG/Canvas 두 렌더러가 단일 진실 원천 공유

4. 디버깅 보강

파일 변경
src/main.rs dump (라인 1643) 표 셀 내부 그림에 orig, cur, crop 출력 추가. Stage 1 조사 단계에서 적용한 후 디버깅 가치로 유지

5. 테두리 문단 inner padding 수정 (커밋 07b6737)

본 브랜치에 함께 포함된 별도 fix 커밋이다.

  • 증상: visible stroke 테두리가 적용된 문단에서 텍스트가 테두리 선에 바짝 붙어 가독성 저하.
  • 수정: visible stroke 테두리 + border_spacing 좌/우 0 인 경우 paragraph margin 값을 inner padding 으로 추가 적용. 박스 위치는 box_margin 으로 분리해 그대로 유지. 배경(fill)만 있는 문단은 영향 없음.
  • 파일: src/renderer/layout/paragraph_layout.rs (+29 / -3)

#430 (이미지 crop) 과는 코드 경로가 분리되어 상호 영향 없음.

검증

단위 테스트 (신규 4건, src/renderer/svg/tests.rs)

  • test_compute_image_crop_src_exam_kor_header — 본 이슈 케이스
  • test_compute_image_crop_src_no_crop_full_image — crop 이 원본 전체와 일치
  • test_compute_image_crop_src_offset_top_left — 좌상단 오프셋 + 우하단 잘림
  • test_compute_image_crop_src_fallback_when_original_size_missing — 폴백 검증

빌드/테스트

항목 결과
cargo build --release (native) 통과
cargo check --target wasm32-unknown-unknown --release --lib (WASM) 통과
cargo test --release --lib 1027 passed, 0 failed
cargo test --release --tests 7 passed, 0 failed
cargo clippy --release --lib 기존 선존재 에러 2건(table_ops.rs:1007, object_ops.rs:298) 외 본 변경 추가 경고 0건

시각 검증

  • exam_kor 1쪽 헤더 — "국어 영역" 만 표시 (PDF 일치) ✓
  • exam_kor 다른 페이지 — 본 변경 전후 동일 동작 ✓

수정 후 SVG 의 헤더 영역:

<svg x="452.07" y="207.25" width="218.37" height="56.71"
     viewBox="0 0 1364.88 354" preserveAspectRatio="none">
  <image width="2320" height="354" href="data:image/jpeg;base64,..."/>
</svg>

viewBox 가 정확히 좌측 1364.88×354 px(= "국어 영역" 영역)만 노출. 원본 JPEG 자체는 그대로 임베드되어 있어 향후 동일 자원 다른 crop 적용에도 재사용 가능.

변경 파일

M src/main.rs                                  (dump 보강, 디버깅 가치로 유지)
M src/renderer/layout.rs                       (ImageNode original_size_hu)
M src/renderer/layout/picture_footnote.rs      (ImageNode original_size_hu × 2 사이트)
M src/renderer/layout/table_cell_content.rs    (필드 명시 보강)
M src/renderer/layout/paragraph_layout.rs      (테두리 문단 inner padding — 별도 fix)
M src/renderer/render_tree.rs                  (ImageNode 필드 추가)
M src/renderer/svg.rs                          (헬퍼 추출 + 공식 교정)
M src/renderer/svg/tests.rs                    (단위 테스트 4건 추가)
M src/renderer/web_canvas.rs                   (시그니처 + 헬퍼 호출)

영향 범위

  • 변경은 FillMode::FitToSize + crop 경로로 한정. crop 이 없는 경우 또는 다른 fill 모드는 영향 없음.
  • original_size_hu = None 폴백 분기를 유지해 채우지 않은 ImageNode 생성 사이트(인라인 TAC picture 등)도 종전 동작 보존.
  • SVG/Canvas 두 렌더러 모두 동일 헬퍼 호출 — 단일 진실 원천.
  • 회귀: exam_kor 다른 페이지 동일 동작 확인 ✓.

비범위 (Out of Scope)

본 이슈 수정 범위 외로 별도 이슈 분리 권장:

  1. 인라인 TAC picture crop 누락paragraph_layout.rs:1700, 1950, 2033 의 ImageNode 생성 사이트는 crop 자체를 전달하지 않음. 본 케이스에서는 미사용 경로지만 동일 패턴 재발 가능.
  2. 그룹/도형 pictureshape_layout.rs:959, 1133 동일.
  3. 섹션 1/2 (페이지 14, 20) 헤더 이미지 미렌더 — 셀 paragraph[1] 이 텍스트((화법과 작문) 등) + 그림(bin_id=27) 동시 보유 시 그림이 SVG 에 출력되지 않음. 본 이슈와 별개로, "텍스트와 그림이 함께 있는 셀 paragraph" 처리 결함.

closes #430

bin_id=27 (exam_kor 헤더) 의 실제 pic.crop 실측:
- orig=174000×26580 HU (=2320×354 px @ 75 HU/px)
- crop=(0, 0, 102366, 26580) → 좌측 58.8% 영역 ("국어 영역"만)
- 시나리오 (A) 확정: HWP에 명시 crop 있으나 렌더러 스케일 공식 오류

src/main.rs:1643 표 셀 그림 dump 형식에 orig/cur/crop 추가 (디버깅).

수행계획서 + 구현계획서 + Stage 1 보고서.
…공식 교정

ImageNode 에 original_size_hu: Option<(u32, u32)> 추가하고
pic.shape_attr.original_{width,height} 값을 채워 보낸다.
- picture_footnote.rs::layout_picture (표 셀 그림 — 본 케이스)
- picture_footnote.rs::layout_body_picture (body picture)
- layout.rs::layout_paragraph 의 TAC+빈 문단 경로

svg.rs 의 crop 스케일 공식 교정:
- 기존: scale_x = cr/img_w → src_w 항상 img_w (crop 무력화)
- 신규: scale_x = original_width_hu/img_w_px (정확한 HU/px)
- 헬퍼 compute_image_crop_src 추출 (pub(crate))
- 폴백: original_size_hu 가 None 이면 기존 공식 유지 (호환성)

단위 테스트 4건 추가:
- exam_kor 헤더 케이스 (174000×26580 HU, crop 좌측 58.8% → src=1364.88×354)
- crop=원본전체 케이스
- 좌상단 오프셋 케이스
- 폴백 검증
draw_image_with_fill_mode 시그니처에 original_size_hu 추가하고
crop 분기에서 svg::compute_image_crop_src 헬퍼 호출로 교체.
SVG/Canvas 두 렌더러가 단일 진실 원천 공유.

검증:
- cargo build --release (native) + cargo check --target wasm32 --lib 통과
- cargo test --release --lib: 1027 passed
- cargo test --release --tests: 7 passed
- exam_kor 페이지 1 헤더 viewBox="0 0 1364.88 354" → "국어 영역" 표시 확인
- clippy 기존 선존재 에러 2건은 본 변경과 무관
exam_kor 헤더 "국어 영역(A 형)" → "국어 영역" 으로 정정 완료.
PDF 정답과 일치.
visible stroke 테두리 + border_spacing 좌/우 0 인 경우 paragraph
margin 값을 inner padding 으로 추가 적용. 박스 위치는 box_margin
으로 분리해 그대로 유지. 배경(fill)만 있는 문단은 영향 없음.
edwardkim added a commit that referenced this pull request Apr 29, 2026
PR #434 / 이슈 #430 검토 중 발견된 정황 — 같은 hwp 를
한컴 2010 / 2020 / 한컴독스가 다르게 조판한다는 사실이
이미지 자동 크롭 영역까지 확장됨.

이 정황과 비교 자료를 모든 컨트리뷰터와 fork 한 사람들이
접근할 수 있도록 README 에 위키 링크 추가:

- Contributing 섹션에 "한컴 PDF 는 정답지가 아닙니다" 항목 추가
- 신규 "위키 자료 (Wiki)" / "Wiki Resources" 서브섹션 추가
  (한컴 PDF 환경 의존성 / HWP 스펙 정오표 / LINE_SEG vpos /
   Tab Leader / Export API / Cloudflared / Hyper-Waterfall /
   Investigation PR / Legal FAQ)

위키 페이지 자체는 별도 commit (rhwp.wiki repository)
으로 발견 정황 II (PR #434) 섹션 보강.
edwardkim added a commit that referenced this pull request Apr 29, 2026
- mydocs/pr/pr_434_review.md (옵션 3: 5 commits 모두 cherry-pick + 한컴 PDF 환경 의존성 II 발견 정황)
- mydocs/pr/pr_434_report.md (cherry-pick 머지 결정 + 위키/README 후속 조치 정리)
- mydocs/orders/20260429.md (PR 처리 + 위키 보강 + samples 추가 + README 보강 행 추가)

검증: 1066 passed + svg_snapshot 6/6 + issue_418 1/1 + clippy 0 + WASM 4,182,395 bytes
광범위 byte 비교: 309 중 40 페이지 변화 (의도된 정정)
한컴 PDF 환경 의존성 II: 한컴 2010 ↔ 2020 ↔ 한컴독스 차이 발견 → 위키 보강 + README 안내
시각 판정: 작업지시자 한컴 3종 PDF + SVG/Canvas 직접 통과
@edwardkim

Copy link
Copy Markdown
Owner

@planet6897 님 PR 감사드립니다. 메인테이너가 cherry-pick 으로 devel 에 적용 완료했습니다.

처리

작성자 attribution 보존 5 commits 모두 cherry-pick (Task #430 4 commits + 별도 fix 1 commit):

  • 060bd5f (← 03906c4) Stage 1: 그림 crop 미적용 원인 정밀 조사
  • ead4a43 (← a5541f9) Stage 2: ImageNode.original_size_hu + svg.rs crop 공식 교정
  • 09f5d0c (← 401f3c5) Stage 3: web_canvas.rs 동기화 + 회귀 검증
  • dfb685d (← 97d18db) Stage 4: 최종 보고서 + 오늘할일 갱신
  • add226a (← 84c8a27) fix(paragraph): 테두리 문단 inner padding — 별도 fix

devel 머지 commit: 27c289b

검증

광범위 byte 단위 비교

10 샘플 / 309 페이지 SVG 비교: 269/309 byte 동일, 40/309 차이 (의도된 정정).

차이 분포: exam_kor 22, exam_eng 8, 2025년 기부 6, synam-001 3, k-water-rfp 1.

시각 판정 (작업지시자 직접) + 한컴 PDF 환경 의존성 II 발견

본 PR 검토 중 작업지시자가 한컴 3종 PDF 자료 제공:

  • samples/2010-exam_kor.pdf (한컴 2010, 4.57 MB)
  • samples/2020-exam_kor.pdf (한컴 2020, 4.57 MB)
  • samples/hancomdocs-exam_kor.pdf (한컴독스, 6.05 MB)

한컴 2010 ↔ 한컴 2020 ↔ 한컴독스 모두 다르게 조판 정황 발견.

작업지시자 코멘트:

"이 시험지를 조판한 사람의 의도에 맞다는 생각이 들 정도입니다."

경로 시각 판정 결과
SVG 통과 ✅
Canvas (rhwp-studio) 통과 ✅

후속 조치 (메인테이너 처리)

  1. 3종 PDF samples/ commit (devel 2714211) — 모든 컨트리뷰터 공유
  2. 위키 페이지 보강한컴 PDF 환경 의존성 에 "발견 정황 II (PR Task #430: 그림 자동 크롭(FitToSize+crop) 공식 교정 — exam_kor 헤더 "국어 영역" 정상 표시 #434 / 이슈 그림 자동 크롭(박스 비율 맞춤) 미구현 — exam_kor 헤더 "국어 영역(A 형)" #430)" 섹션 추가
  3. README.md / README_EN.md 보강 (devel a45c78b) — Contributing 섹션에 "한컴 PDF 는 정답지가 아닙니다" 항목 + 신규 "위키 자료 (Wiki Resources)" 서브섹션

이슈 #430 도 함께 close 됩니다. 본 PR 의 정밀 진단 (잘못된 crop 공식 → 올바른 HU/px 스케일 공식) 과 헬퍼 추출 (SVG/Canvas 단일 진실 원천 공유) 모두 좋은 설계였습니다. 감사합니다.

@edwardkim edwardkim closed this Apr 29, 2026
@planet6897 planet6897 deleted the local/task430 branch April 30, 2026 00:02
edwardkim added a commit that referenced this pull request Apr 30, 2026
작업 시작점: k-water-rfp 16쪽 두 번째 표 셀 안 그림 셀 경계 초과.
시각 검증 중 1쪽 K-water 로고 결함도 발견 → 회귀 origin: PR #434 /
Task #430 (commit a5541f9, @planet6897). 작업 범위 확장 통합.

본질:
  HWP 의 image bin 두 가지 케이스:
  - A: PNG = crop 적용 후 image (k-water-rfp pi=31 등)
  - B: PNG = 원본 image (exam_kor 헤더 등)

  Task #430 의 scale_x = orig_w / img_w_px 계산식이 케이스 B 만 정합,
  케이스 A 회귀 (image 좌측 89.66% 만 보이고 1.069배 stretch = 확대).

정정:
  - compute_image_crop_src: HWP 표준 75 HU/px 룰 단일 계산식
    (1 inch = 7200 HU = 96 px → 75 HU/px = DPI 96)
  - 호출부 셀 폭 클램프 3개소 (table_layout.rs / table_partial.rs /
    shape_layout.rs) — TAC 표 셀 / 도형 안 그림이 셀 폭 초과 시 비율
    유지 클램프

검증:
  - cargo test --lib: 1078 passed (1075 + 단위 테스트 3 추가)
  - svg_snapshot: 6/6, issue_418: 1/1, clippy: 0건
  - 작업지시자 시각 판정: 1쪽 + 16쪽 모두 정상

문서:
  - 트러블슈팅: mydocs/troubleshootings/image_crop_scale_rule.md
  - 위키: HWP 그림 Crop Scale 룰

작업지시자 통찰: "이건 휴리스틱이 아닙니다. 룰입니다."

closes #477

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request Apr 30, 2026
본 사이클 누적 정정 (5):
- Task #474: RowBreak 표 보호 블록 정책 비적용 (k-water-rfp 5쪽)
- Task #477: 표 셀 안 그림 클램프 + 이미지 Crop Scale 룰 정합화 (PR #434/Task #430 회귀)
- Task #470 + #471: cross-column vpos-reset / 박스 stroke_sig (PR #472 cherry-pick)
- Task #431: 분할 표 셀 내 문단 미출력 (단위 mismatch) + dump-pages 진단 도구
- Task #429: 표 셀 배경 image fill 미구현 (BorderFill image_fill 렌더링)

본 사이클 close 이슈 (10):
- 정정 완료: #474 / #477 / #431 / #429
- 자동 해결 / 정합 점검: #426 / #407 / #231 / #345
- 구현 중지: #497 / #242 (클라우드 HWP 인라인 — 본 사이클 외)

마일스톤 v2.0.0 이관 (2): #272 (HwpCtrl Action) / #307 (이미지 드래그 앤 드롭)

샘플 추가:
- samples/exam_eng-2010.pdf, exam_eng-2020.pdf (이슈 #345 정답지)
- samples/hwpx/issue_241.hwpx + pdf (이슈 #241 본질 분석용)

검증:
- cargo test --lib: 1080 passed
- svg_snapshot: 6/6, issue_418: 1/1, clippy: 0건
- WASM 4,204,760 bytes
- 작업지시자 시각 판정 통과 (Task #474 / #477 / #431 / #429)
jangster77 pushed a commit to jangster77/rhwp that referenced this pull request Apr 30, 2026
작업 시작점: k-water-rfp 16쪽 두 번째 표 셀 안 그림 셀 경계 초과.
시각 검증 중 1쪽 K-water 로고 결함도 발견 → 회귀 origin: PR edwardkim#434 /
Task edwardkim#430 (commit a5541f9, @planet6897). 작업 범위 확장 통합.

본질:
  HWP 의 image bin 두 가지 케이스:
  - A: PNG = crop 적용 후 image (k-water-rfp pi=31 등)
  - B: PNG = 원본 image (exam_kor 헤더 등)

  Task edwardkim#430 의 scale_x = orig_w / img_w_px 계산식이 케이스 B 만 정합,
  케이스 A 회귀 (image 좌측 89.66% 만 보이고 1.069배 stretch = 확대).

정정:
  - compute_image_crop_src: HWP 표준 75 HU/px 룰 단일 계산식
    (1 inch = 7200 HU = 96 px → 75 HU/px = DPI 96)
  - 호출부 셀 폭 클램프 3개소 (table_layout.rs / table_partial.rs /
    shape_layout.rs) — TAC 표 셀 / 도형 안 그림이 셀 폭 초과 시 비율
    유지 클램프

검증:
  - cargo test --lib: 1078 passed (1075 + 단위 테스트 3 추가)
  - svg_snapshot: 6/6, issue_418: 1/1, clippy: 0건
  - 작업지시자 시각 판정: 1쪽 + 16쪽 모두 정상

문서:
  - 트러블슈팅: mydocs/troubleshootings/image_crop_scale_rule.md
  - 위키: HWP 그림 Crop Scale 룰

작업지시자 통찰: "이건 휴리스틱이 아닙니다. 룰입니다."

closes edwardkim#477

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@planet6897 planet6897 restored the local/task430 branch May 3, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants