- 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>
10 KiB
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, 즉 wasmmemory.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. 검증 방법
- 파싱 비교 (Node): 기존 wasm 과 새 wasm 으로 같은 DWG 19개를 파싱한다.
fixDwgKoreanText까지 적용한 뒤, 엔티티를타입#handle로 짝짓는다. 필드마다 정규화(숫자 12자리)한 해시로 비교했다. - 브라우저 (Chrome headless, 실 GPU): 같은 작업 트리에서 wasm 만 바꿔 20개(DWG 19 + DXF 1)를 로드한다. 상태바
✓판정, 콘솔 에러, 1280×800 스크린샷 픽셀 비교를 했다. - 네이티브 프로브: 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는 이 샘플들에서 할 일이 없어졌다. 다른 코드페이지 도면 대비용 안전망으로 남겨 둔다.
- 기존 wasm 은 평면및종단면도(153개)와 굴착및시공순서도(160개)를 Latin-1 로 깨진 채 내보냈고,
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 패치)를 보여 준다.