Skip to content

fix(page): write unequal column widths as shares of 32768 - #418

Open
airmang wants to merge 13 commits into
mainfrom
fix/column-widths-as-shares
Open

airmang wants to merge 13 commits into
mainfrom
fix/column-widths-as-shares

Conversation

@airmang

@airmang airmang commented Oct 6, 2026

Copy link
Copy Markdown
Owner

바뀐 점

너비가 다른 단(doc.page.set_columns(same_size=False, column_widths=...))의 너비와 간격을 한/글이 읽는 꼴로 쓴다. 쪽 수 추정(실험, estimate_pages)도 같은 규칙으로 단 너비를 센다.

한/글의 동작

  • hp:colSz의 width와 gap은 HWPUNIT이 아니라 본문 폭을 32768로 나눈 몫이다.
  • 한/글은 단을 width × 본문 폭 / 32768 폭으로 놓는다. 값들의 합이 얼마든 그렇게 놓고, 합으로 나누지 않는다.
  • 한/글이 만든 문서는 합이 늘 32768이다. 그래서 단과 간격이 본문을 꼭 채운다.

고치기 전

  • column_widths를 받은 그대로 썼다.
  • 본문 폭(A4에서 42520)에 맞춰 HWPUNIT으로 준 [(20000, 1000), (21520, 0)]은 한/글에서 단이 약 1.3배 넓게 놓였다(25952, 27925). 둘째 단은 종이 밖까지 나갔다.
  • 쪽 추정은 단 너비를 값들의 합으로 나눠 셌다. 한/글이 만든 문서에서는 결과가 같았고, 합이 32768이 아닌 문서에서만 달랐다.

코드

  • oxml/section_format.py: column_shares와 COLUMN_SHARES(32768)를 더한다.
    • column_widths를 비율로 받아, 같은 비율로 합이 32768이 되는 몫으로 바꾼다. 몫의 경계마다 반올림해서 합이 늘 32768이다.
    • 본문 폭에 맞춘 HWPUNIT 값은 그 너비 그대로 나온다. 합이 이미 32768인 값은 바뀌지 않는다.
    • 값이 0 이상의 int가 아니거나, 모두 0이거나, 쌍이 두 값이 아니면 거부한다. 오류 코드는 page-column-widths-value다.
  • 구역의 단(set_columns), 문단의 새 단(add_column_definition), 퍼사드(doc.page.set_columns)가 무엇도 바꾸기 전에 몫을 구한다.
  • layout/pages.py의 _columns는 단 너비를 width × 본문 폭 / 32768로 센다.
  • errors.py와 docs/error-codes.md에 코드를 등록하고, 변경 로그 항목을 더한다.

테스트

  • tests/test_column_widths_as_shares.py를 더하고, 한/글 저장본 셋을 함께 넣는다.
    • 둘은 같은 두 단을 고치기 전처럼 [(20000, 1000), (21520, 0)](합이 본문 폭)과 [(16000, 768), (16000, 0)](합 32768)로 쓴 것이다. 한/글이 그 단들의 줄을 width × 42520 / 32768 폭으로 놓았는지, 쪽 추정이 같은 폭을 내는지 시험한다.
    • 하나는 [(20000, 1000), (21520, 0)]을 이제 쓰는 몫 [(15413, 771), (16584, 0)]으로 쓴 것이다. 한/글이 줄을 20000과 21520 폭으로 놓았는지 시험한다.
    • HWPUNIT 값이 몫으로 쓰이고, 쪽 추정으로 준 너비 그대로 나오는지 시험한다. 구역의 단과 문단의 새 단을 모두 본다.
    • 이미 몫인 값과 단순 비율이 합 32768로 쓰이는지 시험한다.
    • 잘못된 값이 오류 코드와 함께 거부되고 문서가 그대로인지 시험한다.
  • tests/test_section_columns.py: 너비가 다른 단의 기대값을 몫(15413, 771, 16584, 0)으로 바꾼다.

이 PR은 #415, #416, #417 위에 쌓았다. 앞 PR이 병합되면 그 커밋들은 이 PR의 diff에서 빠진다.

🤖 Generated with Claude Code

airmang and others added 10 commits October 6, 2026 07:25
add_picture wrote any align it was given into hp:pos@horzAlign ("BOGUS",
"  RIGHT ", "TOP"), which Hancom reads as LEFT; a non-string failed only after
the image and its paragraph were added. The alignment is now checked first,
in any case, against the schema's horizontal alignments, and anything else is
refused with shape-position-frame before anything is stored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A negative width or height of a rectangle, ellipse, arc, picture or
equation box, or a negative rectangle corner ratio, was written as given;
Hancom reads it as 0. Such values, and sizes of 2**31 or more, are now
refused with typed errors before any paragraph, run or image is added
(shape-size-value, shape-rect-ratio-value). An equation's base_unit
outside 1..2**31-1 raises shape-equation-base-unit-value (a ValueError,
as before) before its paragraph is added. HwpxOxmlShape.resize refuses a
negative size too, and HwpxOxmlParagraph.add_picture builds the picture
before adding its run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hancom reads a caption's gap and the gap between columns of the same
width as signed 16-bit numbers and a new number as an unsigned one,
wrapping anything else (a column gap of 32768 makes the columns overlap;
a negative one written as text is read as 0). set_caption's gap outside
-32768..32767, a same_gap (or page setup column_gap_mm) outside 0..32767
and a restart number outside 0..65535 are now refused before anything
changes (shape-caption-gap-value, page-column-gap-value,
page-new-num-value). The caption side check moves to shape_position
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hancom reads a column's width and gap (hp:colSz) as a share of the text
width out of 32768 and lays the column out width * text width / 32768
wide, whatever the shares add up to. column_widths were written as
given, so widths in HWP units adding up to the text width came out about
1.3 times as wide and ran off the paper. They are now taken as
proportions and written as shares adding up to 32768 (column_shares);
widths that already add up to 32768 are written unchanged. Negative,
non-int, all-zero or malformed pairs are refused before anything changes
(page-column-widths-value). The page estimate takes a column's width as
its share of 32768 of the text width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
airmang and others added 3 commits October 6, 2026 16:27
add_equation's base unit check now raises a typed error, so
oxml/paragraph.py raises one untyped error fewer. The census lock
records 202 untyped raises (paragraph.py 18), as the ratchet's
self-test expects the lock to match the tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

1 participant