Files
dwg-dxf-viewer-sample/docs/korean-dwg-text-encoding.md

12 KiB
Raw Permalink Blame History

한글 DWG 텍스트 깨짐 — 원인 분석 및 원본 반영 가이드

항목 내용
작성 목적 샘플에서 재현·수정한 이슈를 원본(hmwebviewer) 에 반영하기 위한 기술 메모
샘플 저장소 dwg-dxf-viewer-sample (본 문서 위치)
원본 저장소 hmwebviewer (src/viewer2d/ 동기화 대상)
재현 도면 C0060203-002-굴착및시공순서도(2차로,자연환기300m이상).dwg 등 구형 한글 CAD 도면
대조 도면 BasicSample.dwg (이미 정상 유니코드 한글)
샘플 수정일 2026-07-29
상태 샘플 패치 완료 / 원본 미반영

1. 현상

웹 2D 뷰어에서 일부 DWG를 열면 도형·치수 기하, 영문 TEXT는 정상인데 한글 TEXT/MTEXT·타이틀블록 문구·NOTE 등이 다음과 같이 깨져 보인다.

화면/파서 출력 (깨짐) 정상 의미
½Ã°ø½Ã 시공시
·Ïº¼Æ® 록볼트
¼ôÅ©¸®Æ® 숏크리트
±¼Âø ¹× ½Ã°ø¼ø¼­µµ 굴착 및 시공순서도
Á߽ɼ±(ÀϹÝ) (라인타입 설명) 중심선(일반)

외형상 “폰트가 없다 / 글리프가 없다”와 혼동하기 쉽지만, 글리프 부재(tofu □) 가 아니라 잘못된 유니코드 코드포인트가 그대로 그려진 것(mojibake) 이다.

자주 하는 오진

가설 실제
dist/fonts / public/fonts 에 돋움이 없어서 폰트 폴더에는 NanumGothic-Regular.ttf(한글 포함)가 있음
Style Standard + 폰트 돋움 미매핑 뷰어는 스타일→폰트 매핑 없이 단일 TTF 로 그림. 돋움 없어도 코드포인트만 맞으면 한글 표시 가능
slugText / opentype 버그 동일 파이프라인에서 BasicSample.dwg 한글은 정상

2. 파이프라인 위치

DWG bytes
  → acadrust WASM (parse_dwg)     ← 여기서 문자열이 이미 깨지거나 정상으로 나옴
  → CadParseResult (entities/tables/…)
  → [샘플 패치] fixDwgKoreanText   ← 복원 계층 (원본에는 아직 없음)
  → Viewer2D.load()
  → slugText (NanumGothic TTF)
  → WebGL
  • DXF 경로는 텍스트 파일 디코딩 단계에서 코드페이지를 고려한다.
    • 샘플: src/viewer2d/decodeDxf.ts ($DWGCODEPAGE / 949 → euc-kr 등)
    • 원본: hmwebviewer/src/viewerController.ts 내 유사 decodeDxf
  • DWG 경로는 바이너리 → WASM → JSON 문자열이며, 파싱 직후 한글 코드페이지 보정 계층이 없었다.

관련 모듈:

역할 샘플 경로 원본 경로
DWG 파서 진입점 src/viewer2d/dwgParser.ts hmwebviewer/src/viewer2d/dwgParser.ts
WASM 래퍼 src/viewer2d/acadrustParser.ts 동일
텍스트 렌더 src/viewer2d/slugText.ts 동일
한글 복원 (샘플만) src/viewer2d/fixDwgKoreanText.ts 없음 → 이식 대상

3. 원인 분석

3.1 근본 원인 (Root cause)

구형/한글 CAD DWG에 저장된 CP949(Windows-949) 계열 바이트 시퀀스를, acadrust 파서(또는 그 문자열 경계)가 Latin-1/바이트-단위 유니코드로 승격해 버린 것.

즉:

원본 바이트 (CP949)  --잘못된 해석-->  U+00xx Latin-1 문자들  --렌더-->  깨진 화면
예: EC 8B 9C ... (시) 가  ½ Ã ° ø … 같은 문자로 보임

복원 공식 (검증됨):

broken.encode('latin1')  →  bytes
bytes.decode('cp949' | 'euc-kr' | 'windows-949')  →  정상 한글

브라우저/Node TextDecoder 라벨 우선순위 (샘플 구현):

  1. cp949
  2. windows-949
  3. euc-kr

3.2 왜 도면마다 다른가

도면 파서 직후 TEXT 원인 해석
BasicSample.dwg 설계사, 시공사정상 한글 음절 이미 유니코드/UTF 계열로 저장·추출됨
C0060203-002-….dwg 한글 음절 0건, Latin-1 고위 문자 다수 CP949 레거시 저장 + 오해독

동일 뷰어·동일 폰트에서 결과가 갈리므로 렌더러/폰트 문제가 아님이 확정된다.

3.3 영향 범위 (문자열 필드 전반)

TEXT/MTEXT 본문뿐 아니라 같은 인코딩으로 들어간 메타 문자열도 깨진다.

  • entities[].text (TEXT / MTEXT / ATTRIB 등)
  • tables.lineTypes[].description (예: 중심선, 파선 한글 설명)
  • tables.blocks[].name (예: CXGLOGO-EX흑백CXGLOGO-EXÈæ¹é)
  • 기타 파서가 문자열로 넘기는 테이블/속성 필드

필드 단위 패치보다 parseResult 트리 전체 문자열 walk 가 안전하다.

3.4 부수 관찰 (이번 깨짐의 주원인은 아님)

관찰 의미
tables.styles 가 빈 배열 스타일/폰트명(돋움) 정보를 뷰어가 쓰지 못함. 장기 개선 항목
뷰어 고정 폰트 NanumGothic-Regular.ttf 한글 글리프 보유. 코드포인트만 맞으면 표시됨
UI 파일명·OS 경로 한글 OS 유니코드 경로라 정상일 수 있음. DWG 내부 텍스트와 무관

4. 증거 (재현 절차)

4.1 파서만 돌려 TEXT 통계

WASM 초기화 후 parse_dwg 결과에서:

// TEXT/MTEXT 중 한글 음절 포함 여부
/[\uAC00-\uD7A3]/.test(entity.text)

문제 도면 예 (패치 전):

  • hangul: 0
  • 깨진 Latin: 다수 (½Ã°ø… 패턴)

패치 후:

  • hangul: 다수 (예: 130)
  • NOTE 샘플: 2. 시공시 막장관찰, 계측분석결과, …
  • 라인타입: 중심선(일반) Center …
  • 블록: CXGLOGO-EX흑백

4.2 단위 변환 검증

입력 latin1 바이트 재해석 → CP949
½Ã°ø½Ã 시공시
·Ïº¼Æ® 록볼트
NOTE NOTE (변경 없음)
설계사 휴리스틱상 스킵 (이미 한글)

4.3 음성 대조

BasicSample.dwg 에 동일 복원기를 적용해도 설계사 / 시 공 사 등이 변하지 않아야 한다.


5. 샘플에 적용한 처리 방법

5.1 신규 모듈

src/viewer2d/fixDwgKoreanText.ts

  • fixCp949Mojibake(s: string): string
    단일 문자열 복원
  • fixDwgKoreanText<T>(root: T): T
    parseResult 딥 워크, in-place 수정 후 동일 참조 반환

5.2 휴리스틱 (중요 — 정상 도면 보호)

다음이면 원문 유지:

  1. 빈 문자열
  2. 이미 한글 음절(U+AC00U+D7A3) 또는 자모 포함
  3. 순수 ASCII (모든 코드포인트 ≤ 127)
  4. Latin-1 범위를 넘는 코드포인트 포함 (진짜 유니코드)
  5. 한국 코드페이지 디코더 없음 / 디코드 실패
  6. 디코드 결과에 한글이 없거나 U+FFFD 포함

다음일 때만 교체:

  • 고위 Latin-1(>127) 포함 그리고
  • CP949/EUC-KR 디코드 성공 그리고
  • 결과에 한글 음절/자모 포함 그리고
  • 치환 문자 없음

5.3 삽입 지점

src/viewer2d/dwgParser.ts:

import { fixDwgKoreanText } from './fixDwgKoreanText';

export async function parseDwgBuffer(bytes: Uint8Array): Promise<CadParseResult> {
  const { initAcadrustParser, parseDwgAcadrust } = await import('./acadrustParser');
  await initAcadrustParser();
  return fixDwgKoreanText(parseDwgAcadrust(bytes));
}
  • Viewer2D / slugText / 폰트 설정 변경 불필요
  • DXF 경로 변경 불필요 (이미 별도 디코드)

5.4 왜 WASM 내부 수정이 아닌가 (1차 선택 이유)

접근 장점 단점
JS 후처리 (채택) 배포 단순, acadrust 크레이트 재빌드 없음, 샘플↔원본 이식 쉬움 근본 수정은 아님. 휴리스틱 오탐 가능성(낮음)
acadrust/코드페이지 수정 파서 정합 MPL·Rust/WASM 빌드 체인, 검증 범위 큼
스타일→돋움 TTF 매핑 WYSIWYG 개선 이번 mojibake를 해결하지 못함

중장기적으로는 WASM/파서가 DWG 코드페이지(또는 문자열 유니코드 플래그)를 올바르게 반영하는 것이 이상적이다.
그 전 단계의 제품 적용 가능한 완화책이 JS 후처리다.


6. 원본(hmwebviewer) 반영 절차

원본 src/viewer2d/dwgParser.ts 는 샘플 패치 전과 동일하게 parseDwgAcadrust 결과를 그대로 반환한다.

6.1 최소 이식 (권장 1차)

  1. 샘플에서 복사
    • dwg-dxf-viewer-sample/src/viewer2d/fixDwgKoreanText.ts
    • hmwebviewer/src/viewer2d/fixDwgKoreanText.ts
  2. hmwebviewer/src/viewer2d/dwgParser.ts 에 샘플과 동일하게
    fixDwgKoreanText(parseDwgAcadrust(bytes)) 연결
  3. parseDwgBuffer 를 거치지 않는 다른 진입점이 있으면 동일 후처리 적용
    • 예: 직접 parseDwgAcadrust / parse_dwg 호출부 검색
  4. 검증
    • 문제 DWG: NOTE·공정 문구 한글
    • BasicSample 또는 기존 유니코드 한글 DWG: 회귀 없음
    • 영문·숫자·Sealing 등 ASCII 유지
  5. (선택) 단위 테스트
    • fixCp949Mojibake('½Ã°ø½Ã') === '시공시'
    • fixCp949Mojibake('설계사') === '설계사'
    • fixCp949Mojibake('NOTE') === 'NOTE'

6.2 동기화 정책

README 기준: hmwebviewer/src/viewer2d 가 본가이고 샘플은 형제 복사본이다.
이번 이슈는 샘플에서 먼저 수정했으므로, 원본 반영 후 필요 시 샘플과 다시 맞춘다.

6.3 반영 체크리스트

  • fixDwgKoreanText.ts 원본 트리에 추가
  • dwgParser.ts 후처리 연결
  • 직접 WASM 호출 경로 없음 확인
  • 문제 한글 DWG 수동 확인
  • 정상 유니코드 한글 DWG 회귀 확인
  • (선택) DXF ANSI_949 도면도 기존 decodeDxf 동작 유지 확인
  • (선택) tables.styles / 폰트 매핑은 별 이슈로 분리

7. 하지 말아야 할 것

비권장 이유
돋움 TTF만 추가하고 끝 문자열이 깨진 상태면 돋움으로도 동일 mojibake
모든 문자열을 무조건 CP949 디코드 정상 유니코드·라틴 확장 도면 손상
렌더러에서 글리프 폴백만 강화 코드포인트 자체가 틀림
dist 만 수동 패치 소스는 src/; 빌드 산출물에만 고치면 재빌드 시 소실

8. 잔여 이슈 / 후속 과제

  1. 파서 본가 수정
    acadrust(또는 문자열 추출 경로)에서 DWG 코드페이지·유니코드 플래그 반영 → JS 휴리스틱 제거 가능 여부 검토
  2. STYLE 테이블
    현재 tables.styles 가 비어 스타일/폰트명 미노출. 돋움 등 CAD 지정 폰트 매핑은 별 과제
  3. 다른 코드페이지
    일본(932)/중국(936)/대만(950) 도면에 동일 패턴이 있으면 라벨 확장 + 문자 체계 휴리스틱 필요 (현 구현은 한글 음절 출현 조건으로 한국 도면에 한정)
  4. ATTRIB / 치수 상주 텍스트 등
    딥 워크로 대부분 커버되나, 바이너리/비문자열 필드는 대상 외

9. 한 줄 요약

폰트 폴더 문제가 아니라, 구형 한글 DWG의 CP949 바이트가 Latin-1 문자열로 올라온 인코딩 오해독이다.
parse_dwg 직후 문자열 트리를 CP949로 재해석(이미 한글인 값은 스킵)하면 해결되며,
원본 hmwebviewer 에는 샘플의 fixDwgKoreanText.ts + dwgParser.ts 연결을 그대로 이식하면 된다.


10. 참고 파일 (샘플)