Files
dwg-dxf-viewer-sample/docs/acadrust-0.6.5-upgrade.md
T
minsungandClaude Opus 5.5 e51114dbfd docs: record the acadrust 0.6.5 upgrade with a capture comparison report
- acadrust-0.6.5-upgrade.md: what changed in dwg-wasm and why (failsafe
  reads, 32 MiB wasm memory growth, API changes), the field-level parse
  diff with each cause, cost (wasm size, load time) and what is left.
- acadrust-0.6.5-upgrade-report.html: self-contained report with old/new
  captures of all 22 samples, zoomed checks of the formerly patched MESH
  and OLE2FRAME paths, and a diff image for each of the 5 changed views.
- license-mpl2-acadrust.md / README: the obligation is now license text
  plus source location; records why the 0.4.1 notice was wrong.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 19:44:15 +09:00

10 KiB
Raw Blame History

acadrust 0.4.1(패치) → 0.6.5(무수정) 업그레이드

항목 내용
날짜 2026-10-19
목적 로컬 패치를 없애 MPL-2.0 의무를 "고지 + 소스 링크"로 줄인다 (license-mpl2-acadrust.md)
Rust 쪽 변경 hmwebviewer 브랜치 chore/acadrust-0.6.5 (feat/subdmesh-render 에서 분기)
이 레포 변경 src/viewer2d/acadrust-dwg/ wasm 교체, 고지·문서 갱신
상태 수정 완료·검증됨 (샘플 20개 파싱 비교 + 브라우저 로드·스크린샷)
캡처 보고서 acadrust-0.6.5-upgrade-report.html — 샘플 22개 기존/신규 화면 비교 (이미지 내장)

1. 결론

  • acadrust 를 고치지 않고도 기존 두 수정(MESH, OLE2FRAME)의 결과가 그대로 나온다.
  • 화면 회귀는 없다. 패널을 숨기고 도면만 찍은 최종 캡처 기준으로, 샘플 22개 중 17개는 기본 화면이 픽셀 단위로 같다. 나머지 5개의 차이는 모두 데이터가 더 정확해진 결과다 (§4, 캡처 보고서). §4 의 스크린샷 표는 툴바가 함께 찍힌 첫 캡처 기준이라 탭 이름 차이가 섞여 있다.
  • 대가: wasm 이 커졌고 (brotli 294 → 815 KB), 대형 도면 파싱이 10~16% 느려졌다 (§5).

2. dwg-wasm 변경 (우리 MIT 코드)

변경 이유
acadrust = "=0.6.5" (crates.io, 정확한 버전 고정), vendored rust/acadrust/ 삭제 무수정 사용. 고지에 적은 버전과 빌드 소스를 일치시킨다
match d.as_ref() 0.6 에서 EntityType::Dimension 이 Box<Dimension> 으로 바뀜
DIMENSION_ARC, DIMENSION_LARGE_RADIAL 타입명 추가 0.6 이 새로 읽는 치수. 0.4 는 버렸고, Viewer2D 는 아직 이 이름을 그리지 않으므로 화면은 전과 같다
OLE: o.binary_data → o.encoded_payload() 0.6 은 OLE 페이로드를 envelope + compound file 로 분해해 둔다. 재조립한 바이트로 기존 DIB 탐색을 한다. 추출 이미지는 기존과 바이트 단위로 같다
DwgReadOptions::failsafe() 0.6 strict 모드는 레코드 하나가 깨져도 도면 전체를 거부한다. a. 거더배치 삽도 가 handle 0x2663(type 37)의 잘못된 배열 개수로 통째로 실패했다. failsafe 에서는 정상 로드되고, 건너뛴 레코드는 notifications 로 간다
전역 할당자: dlmalloc 을 32 MiB 단위로 확장 아래 §2.1

2.1 wasm 메모리 확장 비용

0.6.5 를 그대로 올리면 37 MB 노면 도면 파싱이 Node 에서 3.0초 → 7.4초로 느려졌다.

  • 원인 확정 (CPU 프로파일): 시간의 55% 가 <dlmalloc::sys::System as Allocator>::alloc, 즉 wasm memory.grow 에 있었다.
  • V8 에서 memory.grow 한 번의 비용은 늘리는 양이 아니라 현재 메모리 크기에 비례한다 (Node 24 실측: 16 MB 일 때 0.04 ms, 700 MB 일 때 1.6 ms).
  • 0.6 은 짧게 쓰고 버리는 버퍼가 많아서, 기본 dlmalloc(64 KB 페이지 단위)이 수천 번 확장했다.

dwg-wasm/src/lib.rs 의 big_step_alloc 이 같은 dlmalloc 을 set_granularity(32 MiB) 로 감싸서 해결한다. acadrust 는 건드리지 않는다. 결과는 7.4초 → 3.3초. 대신 힙 끝에 최대 한 단계(32 MB)가 비어 있을 수 있다.

3. 검증 방법

  1. 파싱 비교 (Node): 기존 wasm 과 새 wasm 으로 같은 DWG 19개를 파싱한다. fixDwgKoreanText 까지 적용한 뒤, 엔티티를 타입#handle 로 짝짓는다. 필드마다 정규화(숫자 12자리)한 해시로 비교했다.
  2. 브라우저 (Chrome headless, 실 GPU): 같은 작업 트리에서 wasm 만 바꿔 20개(DWG 19 + DXF 1)를 로드한다. 상태바 ✓ 판정, 콘솔 에러, 1280×800 스크린샷 픽셀 비교를 했다.
  3. 네이티브 프로브: MESH/OLE2FRAME 값을 원본 0.4.1 · 패치본 · 0.6.5 로 비교했다 (license-mpl2-acadrust.md §3).

4. 결과

파싱: 19/19 성공. 파일별 엔티티 수와 handle 집합이 완전히 같다 (354,502개 중 누락·추가 0). 필드 값이 바뀐 엔티티는 2,815개(0.79%)다.

바뀐 필드 건수 / 파일 원인 화면 영향
DIMENSION_*.pt10 1,168 / 9 0.4.1 이 정의점을 (0,0,0) 으로 냈다 → 실제 좌표 블록 없는 치수(fallback)의 선택 범위·extents 만
ATTDEF alignmentPt / horiz·vertAlignment / widthFactor 최대 664 / 13 0.4.1 이 읽지 못했다 → 실제 값 블록 안 ATTDEF 텍스트 위치·폭이 정확해진다
INSERT.blockName, tables.blocks 이름 812 / 1 (ELEVATION) 익명 블록 번호 체계가 바뀜 (*U1 → *U7) 없음. 렌더는 handle 기준이고, INSERT 이름과 블록 테이블 이름은 전 파일에서 일치(불일치 0)
entityHeader.colorIndex (트루컬러 엔티티) 116 / 3 트루컬러 → 가장 가까운 ACI 근사가 개선됨. 원본 RGB 는 같다 원본 RGB 에 더 가까운 색 (Viewer2D 팔레트 기준 거리 130.8→117.6, 51.5→24.7)
VIEWPORT.id 0 → 1 27 / 10 0.6.5 가 레이아웃의 전체(paper) 뷰포트에 id 1 을 준다 7개 파일에서 전체 뷰포트를 모델 창으로 오판하던 것이 사라졌다 (아래)
VIEWPORT.status.bits 26 / 2 비트 0x10000 추가 없음 (Viewer2D 는 isOn 만 사용)
TEXT.text 1 / 1 500¡¿350 → 500×350 CP949 기호 깨짐 1건 해소
OLE2FRAME.dataLength 1 / 1 페이로드 재조립으로 512 B 차이 없음 (이미지 바이트 동일)
vars.celweight 전 파일 29 → -1 없음 (미사용)

VIEWPORT 판정: id 가 1 로 바뀐 VP 는 모두 레이아웃마다 하나뿐인 전체 뷰포트였다 (배율 1.0000, target (0,0)). 진짜 모델 창(id ≥ 2)의 판정은 전 파일에서 그대로다.

기존에는 Viewer2D._isModelViewport 의 휴리스틱이 이 VP 를 모델 창으로 오판했다. 판정 조건 중 "viewCenter ≈ center" 가 맞지 않았기 때문이다. 그래서 모델 공간을 레이아웃 위에 한 번 더 투영했다. a. 중앙분리대 삽도 의 기본 화면을 가로지르던 검은 세로 띠가 이것이고, 업그레이드 후 사라졌으며 Fit 도 도면을 제대로 채운다.

브라우저: 기존·신규 모두 20/20 로드 성공. 기본 탭(Model/Layout) 동일, 콘솔 에러 동일 (첫 페이지 favicon 404 1건).

스크린샷 차이 파일 내용
0% (픽셀 동일) 16개 —
16.9% a. 중앙분리대 삽도 검은 띠 제거, Fit 개선, 해치 갈색이 원본 RGB 에 가까워짐
3.3% / 0.5% a. 교량시종점 / a. 횡단경사 트루컬러 근사색
0.6% / 0.005% a. 교량폭원 / ELEVATION 툴바의 Layout 탭 이름 폭

Layout 탭 이름은 익명 paper 블록 번호를 따르므로 바뀌었다 (Paper_Space1 → Paper_Space194 등). 원래 내부 이름이 보이던 문제(레이아웃 실제 이름 미사용)는 그대로다.

notification 수는 4개 파일에서 늘었다 (BasicSample 4→24, 거더배치 5→11 등). 0.6.5 가 진단을 더 많이 남기는 것이다.

4.1 추가 샘플 (public/samples/ 신규 3개)

dwg_18.3mb.dwg 는 dist2/samples 의 같은 파일(md5 동일)이라, 실제 신규는 2개다: C0060203-002-굴착및시공순서도, dwg_1.60mb.dwg.

  • 3개 모두 기존·신규 파싱 성공이다. 0.6.5 strict 모드에서도 실패하지 않는다. 엔티티 수와 handle 집합이 같고, 브라우저 로드 성공, 콘솔 에러 0이다.
  • 3D 폴리선 vertex 순서 (dwg_1.60mb, 옹벽·관로 7개, 원인 확정).
    • 두 버전 모두 vertex 13개는 같고 순서만 다르다.
    • 0.4.1 은 vertex 를 handle 번호 순으로 정렬했다. 그래서 나중에 추가된 vertex(handle 227026, 가장 서쪽 점)가 중간에 끼어들어, 선이 최대 193 단위 되돌아갔다 오는 가짜 현(chord)이 생겼다.
    • 0.6.5 는 DWG 연결 순서를 따른다 (x 가 단조 증가하는 매끈한 선). 확대 캡처에서 곡선을 가로지르던 청록 직선이 사라진 것을 확인했다.
  • ATTDEF 정렬: 굴착및시공순서도의 동그라미 번호가 원의 아래쪽에서 중앙으로 옮겨졌다 (§4 의 ATTDEF 행과 같은 원인).
  • 한글: 0.6.5 는 CP949 를 원본에서 직접 디코딩한다.
    • 기존 wasm 은 평면및종단면도(153개)와 굴착및시공순서도(160개)를 Latin-1 로 깨진 채 내보냈고, fixDwgKoreanText 가 복원해 왔다.
    • 0.6.5 는 21개 DWG 전부 원본 깨짐 0이다. 보정 후 한글 텍스트 수는 전 파일에서 같다.
    • fixDwgKoreanText 는 이 샘플들에서 할 일이 없어졌다. 다른 코드페이지 도면 대비용 안전망으로 남겨 둔다.

5. 비용

항목 0.4.1 패치본 0.6.5
wasm raw / brotli 864 KB / 294 KB 2,976 KB / 815 KB
노면 37 MB 파싱 (Node) 3.0 s 3.3~3.5 s
dwg_18.3mb 파싱 (Node) 1.9 s 2.1 s
노면 브라우저 로드 5.4 s 5.7 s
dwg_18.3mb 브라우저 로드 3.7 s 4.0 s
wasm 메모리 (노면 / dwg_18.3mb) 672 / 546 MB 773 / 505 MB
  • 크기가 커진 원인: acadrust 0.6 이 DXF/DWG 쓰기, ACIS 등을 포함해 라이브러리 자체가 커졌다. 기본 feature 는 비어 있어 끌 수 있는 것이 없다.
  • opt-level = "z" 를 시험했다: brotli 742 KB(−9%) 대신 파싱이 36% 느려져서(3.5 → 4.7 s) 채택하지 않았다.

6. 남은 것

  • Viewer2D 가 DIMENSION_ARC / DIMENSION_LARGE_RADIAL 을 그리지 않는다. 블록 렌더 분기에 추가하면 된다. 샘플 20개에는 해당 엔티티가 없다.
  • XDATA: acadrust 는 common.extended_data 로 읽지만 dwg-wasm 이 parseResult 에 내보내지 않는다 (업그레이드 전과 같다).
  • wasm 에 컴파일되는 Rust 의존성의 라이선스 고지 생성 (license-mpl2-acadrust.md §6).
  • dist2/ 재빌드와 pages.dev 재배포 전까지는 배포본이 옛 고지(0.4.1 패치)를 보여 준다.