logo
HWPJS
  • 가이드
  • API
  • 명세서
  • 로드맵
  • 백로그
    백로그
    백로그 개요
    현재 작업
    Previous page백로그 개요

    #현재 작업

    현재 진행 중이거나 곧 시작할 작업 항목들입니다.

    #지원 예정 함수

    #이미지 추출 함수

    • 함수명: extract_images
    • NAPI 함수명: extract_images (node/web/react-native 공통)
    • 기능: HWP 문서에서 이미지를 추출
    • 반환 타입: 옵션으로 파일 경로 리스트 또는 이미지 데이터(바이트) 배열 지원
    • TypeScript 선언: extractImages(data: Array<number>, options?: ExtractImagesOptions): ExtractImagesResult
    • 관련 함수: extract_images_to_dir (디렉토리에 저장하는 버전)
    • 버전: 0.1.0-rc.2부터 지원 예정
    • 상태: 계획됨
    • 구현 위치:
      • Rust: crates/hwp-core/src/viewer/image.rs (새 파일)
      • NAPI 바인딩: packages/hwpjs/src/lib.rs
      • TypeScript: packages/hwpjs/index.d.ts

    반환 형식:

    interface ExtractImagesResult {
      images: Array<{
        id: string;
        data: Uint8Array;
        format: string; // "jpg", "bmp", "png" 등
      }>;
      paths?: string[]; // output_dir 옵션 사용 시
    }

    #문서 요약 정보 함수

    • 함수명: parse_summary_information_json
    • NAPI 함수명: parse_summary_information_json (node/web/react-native 공통)
    • 기능: HWP 문서에서 SummaryInformation을 파싱하여 JSON으로 반환
    • 반환 타입: JSON 문자열
    • TypeScript 선언: parseSummaryInformationJson(data: Array<number>): string
    • 버전: 0.1.0-rc.2부터 지원 예정
    • 상태: Rust 구현 완료, 바인딩 필요
    • 구현 위치:
      • Rust: crates/hwp-core/src/lib.rs (완료)
      • NAPI 바인딩: packages/hwpjs/src/lib.rs (필요)
      • Node CLI: examples/cli/ (필요)
      • Web: examples/web/ (필요)
      • TypeScript: packages/hwpjs/index.d.ts (필요)

    반환 형식:

    interface SummaryInformation {
      title?: string;
      subject?: string;
      author?: string;
      keywords?: string;
      comments?: string;
      last_saved_by?: string;
      revision_number?: string;
      last_printed?: string;
      create_time?: string;
      last_saved_time?: string;
      page_count?: number;
      date_string?: string;
      para_count?: number;
    }

    #개선 작업

    #배포 패키지 용량 최적화

    • 현재 상태: npm 패키지 크기가 131.67 MB (이전 205.10 MB에서 약 36% 감소)
      • 주요 원인: React Native용 .a 정적 라이브러리 파일들이 여러 아키텍처에 대해 포함됨
      • Android: arm64-v8a, armeabi-v7a, x86, x86_64 (4개 아키텍처)
      • iOS: ios-arm64, ios-arm64_x86_64-simulator (2개 아키텍처)
    • 목표: 패키지 크기를 100MB 이하로 줄이기
    • 완료된 최적화:
      1. Rust 빌드 최적화 ✅:
        • 루트 Cargo.toml에 [profile.release] 추가 (workspace 전체 적용)
          • lto = "fat" (Link Time Optimization - 공격적 최적화)
          • strip = true (모든 디버그 정보 제거)
          • codegen-units = 1 (단일 코드 생성 단위)
          • opt-level = "z" (최대 크기 최적화)
          • panic = "abort" (unwind보다 작음)
        • crates/hwp-core/Cargo.toml에도 동일한 최적화 적용
      2. 빌드 산출물 제외 강화 ✅:
        • package.json의 files 필드에 추가 제외 항목:
          • !android/build/**
          • !android/.cxx/**
          • !android/.gradle/**
          • !android/.idea/**
          • !ios/build/**
          • !ios/Pods/**
          • !ios/*.xcworkspace
          • !**/*.log
      3. Android CMake 빌드 최적화 ✅:
        • packages/hwpjs/android/build.gradle의 release 빌드에 최적화 플래그 추가:
          • cppFlags "-O3 -flto -ffunction-sections -fdata-sections"
    • 최적화 결과:
      • 이전 크기: 205.10 MB
      • 현재 크기: 131.67 MB
      • 감소량: 약 73.43 MB (36% 감소)
      • 총 파일 수: 237개
    • 추가 최적화 가능 방법: 4. 선택적 아키텍처 제외 (트레이드오프):
      • Android x86, x86_64 제외 시 약 37MB 추가 감소 가능
      • 하지만 에뮬레이터 사용 불가능해짐
      • 대안: postinstall 스크립트로 GitHub Releases에서 선택적 다운로드
      1. 의존성 최적화:
        • default-features = false 적용으로 추가 3-7% 감소 가능
      2. 링커 플래그 추가:
        • --gc-sections, --as-needed 플래그로 추가 2-5% 감소 가능
    • 영향 범위:
      • Cargo.toml (workspace 루트)
      • crates/hwp-core/Cargo.toml
      • packages/hwpjs/package.json (files 필드)
      • packages/hwpjs/android/build.gradle
      • packages/hwpjs/scripts/check-package-size.sh
    • 참고사항:
      • .a 파일 크기는 최종 앱 번들 크기에 직접적으로 영향을 줌
      • React Native 앱 빌드 시 .a 파일이 앱 번들에 포함됨
      • 따라서 패키지 크기 최적화는 앱 번들 크기 최적화로도 이어짐
    • 우선순위: 높음
    • 상태: 진행 중 (131.67 MB → 목표 100MB 이하)

    #Craby 심링크(symlink) 기능 추가

    • 현재 상태: packages/hwpjs/target 디렉토리가 별도로 생성되어 빌드 아티팩트가 중복 저장됨
    • 변경 필요: Craby 빌드 시 target 디렉토리를 workspace 루트의 target으로 심링크하도록 옵션 추가
    • 목적:
      • 빌드 아티팩트 중복 저장 방지
      • 디스크 공간 절약
      • 빌드 캐시 공유로 빌드 시간 단축
    • 구현 방법:
      • craby.toml에 target_symlink 옵션 추가
      • 옵션 값: true (기본값: false)
      • 빌드 전에 자동으로 심링크 생성
    • 설정 예시:
      [project]
      name = "hwpjs"
      source_dir = "src-reactnative"
      target_symlink = true  # workspace 루트의 target으로 심링크
      
      [android]
      package_name = "rs.craby.hwpjs"
      
      [ios]
    • 영향 범위:
      • Craby 빌드 시스템 수정 필요
      • packages/hwpjs/scripts/create-target-link.ts 스크립트를 Craby에 통합
      • Windows 환경에서 관리자 권한 필요 시 경고 메시지 표시
    • 고려사항:
      • Windows에서는 mklink /D 명령어 사용 (관리자 권한 필요)
      • macOS/Linux에서는 ln -s 사용
      • 기존 target 디렉토리가 존재하는 경우 처리 방법 결정 필요
      • 심링크 생성 실패 시 일반 디렉토리로 폴백
    • 우선순위: 중간
    • 상태: 계획됨

    #이미지 렌더링 크기 정보 추가

    • 현재 상태: toMarkdown과 extract_images 함수가 이미지 데이터만 반환하고, 실제 HWP 문서에서 렌더링되는 크기 정보는 포함하지 않음
    • 변경 필요: 이미지의 실제 렌더링 크기 정보를 반환하도록 개선
      • HWP 문서에서 이미지가 표시되는 실제 크기 (너비, 높이)
      • HWPUNIT 단위로 저장된 크기 정보를 픽셀 또는 밀리미터로 변환
    • 영향 범위:
      • ImageData 구조체에 width, height 필드 추가 (옵션)
      • Rust: crates/hwp-core/src/document/bodytext/shape_component_picture.rs에서 크기 정보 추출
      • NAPI 바인딩: packages/hwpjs/src/lib.rs의 ImageData 구조체
      • TypeScript 타입 정의: packages/hwpjs/dist/index.d.ts
    • 구현 방법:
      • ShapeComponentPicture에서 border_rectangle_x, border_rectangle_y의 크기 정보 추출
      • HWPUNIT을 픽셀 또는 밀리미터로 변환 (DPI 정보 필요할 수 있음)
      • ImageData에 width?: number, height?: number 필드 추가 (옵션)
      • 크기 정보가 없는 경우 undefined 반환
    • 고려사항:
      • HWP 문서의 DPI 설정에 따라 실제 픽셀 크기가 달라질 수 있음
      • 기본 DPI 값 (예: 96 DPI 또는 72 DPI) 사용 여부 결정 필요
      • 이미지 원본 크기와 렌더링 크기가 다를 수 있음
      • border_rectangle_x와 border_rectangle_y의 차이로 인한 크기 계산 방법 결정 필요
    • 우선순위: 중간
    • 상태: 계획됨

    #ArrayBuffer 지원 구현 (코드젠 버그로 인한 커스텀 수정)

    • 문제 상황: Craby 코드젠이 생성한 bridging-generated.hpp에서 ArrayBuffer를 rust::Vec<uint8_t>로 변환하는 코드가 크래시 발생
      • 생성된 코드: vec.reserve(size); std::memcpy(vec.data(), data, size);
      • 문제: CXX 브릿지의 rust::Vec는 set_len이 private이어서 reserve만으로는 크기가 설정되지 않음
      • 결과: memcpy가 유효하지 않은 메모리에 접근하여 크래시 발생
    • 커스텀 수정 내용:
      • packages/hwpjs/crates/lib/src/ffi.rs에 create_vec_from_slice 함수 추가
        • ArrayBuffer를 rust::Vec<uint8_t>로 안전하게 변환하는 Rust 함수
        • data.to_vec()를 사용하여 최적화된 메모리 복사 수행
      • packages/hwpjs/cpp/bridging-generated.hpp에서 createVecFromSlice 사용하도록 수정
        • 코드젠이 생성한 memcpy 방식 대신 Rust 함수 호출로 변경
        • C++에서 ArrayBuffer를 받아 rust::Slice<const uint8_t>로 변환
        • Rust 함수를 호출하여 안전하게 rust::Vec<uint8_t> 생성
      • iOS/Android 모두 동일한 커스텀 수정 적용
    • 수정 이유:
      • CXX 브릿지의 rust::Vec는 set_len이 private이어서 직접 memcpy 사용 불가
      • Rust 함수를 통해 벡터 생성하여 메모리 안전성 보장
      • 성능: Rust의 to_vec()이 SIMD 최적화 가능하여 충분히 빠름
    • 영향 범위:
      • packages/hwpjs/crates/lib/src/ffi.rs: create_vec_from_slice 함수 추가 (커스텀)
      • packages/hwpjs/cpp/bridging-generated.hpp: Bridging<rust::Vec<uint8_t>> 수정 (커스텀)
      • packages/hwpjs/src-reactnative/NativeReactNative.ts: ArrayBuffer 타입 사용
      • examples/react-native/src/App.tsx: ArrayBuffer 변환 로직 수정
    • 상태: 코드젠 버그로 인해 커스텀 수정 완료 ⚠️

    #Craby에 객체 배열(Object[]) 지원 추가

    • 현재 상태: Craby가 객체 배열을 지원하지 않음. 예: Array<ImageData> 형태의 타입을 인식하지 못함
    • 문제 상황:
      • ToMarkdownResult 인터페이스에서 images: ImageData[] 형태를 사용할 수 없음
      • 중첩된 타입 참조(ToMarkdownResult 내부의 ImageData[])를 인식하지 못함
      • 에러: ERROR [as_rs_type] Unsupported type annotation: Ref(RefTypeAnnotation { ref_id: ReferenceId(0), name: "ImageData" })
    • 임시 해결책:
      • ToMarkdownResult에서 images 필드를 제거하고 마크다운만 반환
    • 변경 필요: Craby에 객체 배열 타입 지원 추가
    • 목적: React Native 바인딩에서 복잡한 객체 구조를 반환할 수 있도록 개선
    • 영향 범위:
      • Craby 라이브러리 자체 수정 필요
      • React Native 바인딩: to_markdown 함수의 반환 타입 수정 가능
    • 우선순위: 중간
    • 상태: 계획됨

    #Example 예시 및 E2E 환경 설정

    • 현재 상태: 예제 코드가 기본적인 수준이며, E2E 테스트 환경이 완전히 구축되지 않음
    • 변경 필요:
      • 각 플랫폼별 예제 코드 보완 및 개선
      • E2E 테스트 환경 설정 및 테스트 케이스 작성
    • 구현 범위:
      • 예제 코드 개선:
        • examples/node/: 다양한 사용 시나리오 예제 추가
        • examples/web/: 인터랙티브 데모 기능 강화
        • examples/react-native/: 실제 앱에서 사용할 수 있는 완성도 높은 예제
        • 각 예제에 에러 처리, 로딩 상태, 다양한 옵션 사용 예시 포함
      • E2E 테스트 환경 설정:
        • Node.js E2E 테스트:
          • Vitest 설정 및 테스트 스크립트 작성
          • 실제 HWP 파일을 읽어서 파싱하는 테스트
          • toJson(), toMarkdown(), fileHeader() 함수 테스트
          • 다양한 HWP 파일 형식에 대한 테스트
        • Web E2E 테스트:
          • Playwright 또는 Puppeteer 설정
          • 브라우저 환경에서 WASM 빌드 동작 확인
          • 파일 업로드 및 변환 결과 확인 테스트
          • toJson(), toMarkdown(), fileHeader() 함수 테스트
        • React Native E2E 테스트:
          • Maestro 설정 및 테스트 플로우 작성
          • iOS/Android 실제 디바이스/에뮬레이터에서 테스트
          • 파일 읽기 및 파싱 결과 확인 테스트
          • toJson(), toMarkdown(), fileHeader() 함수 테스트
    • 테스트 도구:
      • Node.js: Vitest
      • Web: Playwright 또는 Puppeteer
      • React Native: Maestro
    • 영향 범위:
      • 예제 코드: examples/ 디렉토리
      • 테스트 스크립트 추가: package.json
      • CI/CD 파이프라인 업데이트: .github/workflows/
      • 테스트 파일: tests/e2e/ 또는 각 예제 프로젝트 내
      • 문서: docs/docs/guide/examples.md 업데이트
    • 우선순위: 중간
    • 상태: 계획됨

    #알 수 없는 요소 (미지원 기능)

    #알 수 없는 Ctrl ID

    • 요소: CtrlHeaderData::Other
    • 설명: 표 127, 128의 알 수 없는 컨트롤 ID들
    • 현재 상태: 파서에서 "Other"로 처리되는 미지원 컨트롤들
    • 위치: crates/hwp-core/src/document/bodytext/ctrl_header.rs:580
    • 우선순위: 낮음
    • 상태: 조사 필요

    #알 수 없는 Shape Component

    • 요소: ShapeComponentUnknown
    • 설명: 알 수 없는 개체 타입
    • 현재 상태: 현재 테스트되지 않은 상태
    • 위치: crates/hwp-core/src/document/bodytext/shape_component_unknown.rs
    • 우선순위: 낮음
    • 상태: 조사 필요

    #알 수 없는 필드 타입

    • 요소: FIELD_UNKNOWN ("%unk")
    • 설명: 알 수 없는 필드 타입
    • 위치: crates/hwp-core/src/document/bodytext/ctrl_header.rs:91
    • 우선순위: 낮음
    • 상태: 조사 필요

    #명세서 문서화 작업 예정

    #차트 형식 명세서 작성

    • 파일: docs/docs/spec/chart.md
    • 현재 상태: 내용 준비 중
    • 작업 내용: HWP 파일 형식의 차트 개체에 대한 명세서 작성
    • 참고: HWP 5.0 명세서의 "4.3.9.6. 차트 개체" 섹션 참조
    • 우선순위: 중간
    • 상태: 작업 예정

    #배포용 문서 형식 명세서 작성

    • 파일: docs/docs/spec/distribution.md
    • 현재 상태: 내용 준비 중
    • 작업 내용: HWP 파일 형식의 배포용 문서 데이터에 대한 명세서 작성
    • 참고: HWP 5.0 명세서의 "4.2.13. 배포용 문서 데이터" 섹션 참조
    • 우선순위: 중간
    • 상태: 작업 예정

    #HWP 3.0 / HWPML 형식 명세서 작성

    • 파일: docs/docs/spec/hwp-3.0-hwpml.md
    • 현재 상태: 내용 준비 중
    • 작업 내용: HWP 3.0 및 HWPML 형식에 대한 명세서 작성
    • 참고: HWP 5.0 명세서의 "본 문서에 대하여" 섹션에서 언급
    • 우선순위: 낮음
    • 상태: 작업 예정

    #알려진 버그

    #noori.md 테이블 텍스트 중복 문제

    • 문제: noori.md 파일에서 테이블 셀 내부의 텍스트가 중복으로 출력되는 문제
    • 증상:
      • 테이블 셀 내부의 텍스트가 테이블 내부와 외부에 모두 출력됨
      • 이미지도 중복으로 출력되는 경우가 있음
    • 원인:
      • 테이블 셀 내부의 ParaText와 ShapeComponentPicture가 테이블 렌더링과 일반 문단 렌더링에서 모두 처리됨
      • 테이블 셀 내용과 캡션을 구분하는 로직이 완벽하지 않음
    • 해결 방법:
      • 테이블 셀 내부의 텍스트와 이미지 ID를 수집하여 중복 출력 방지
      • 텍스트 내용 비교를 통해 테이블 셀 내용과 캡션 구분
      • collect_text_and_images_from_paragraph 함수를 사용하여 재귀적으로 모든 중첩된 레코드 확인
    • 영향 범위:
      • crates/hwp-core/src/viewer/markdown/document/bodytext/paragraph.rs의 CtrlHeader 처리 로직
      • crates/hwp-core/src/viewer/markdown/collect.rs의 collect_text_and_images_from_paragraph 함수
    • 우선순위: 높음
    • 상태: 부분 해결됨 (추가 검증 필요)

    #각주/미주 파싱 버그

    • 문제: 각주/미주 개수는 제대로 맞추나 텍스트와 위치가 첫번째 것으로 중복되어 파싱되는 버그
    • 증상:
      • 각주/미주 컨트롤 헤더의 개수는 올바르게 파싱됨
      • 하지만 각각의 텍스트 내용과 위치 정보가 모두 첫번째 각주/미주의 것으로 중복되어 파싱됨
      • 예: "각주입니다", "각주 두번째입니다"가 모두 "각주입니다"로 파싱됨
    • 원인: LIST_HEADER 파싱 시 원본 데이터에서 같은 데이터를 가진 첫번째 LIST_HEADER를 찾아서 잘못된 문단을 읽고 있음
    • 영향 범위:
      • crates/hwp-core/src/document/bodytext/mod.rs의 LIST_HEADER 파싱 로직
      • 각주/미주 컨트롤 헤더의 자식 LIST_HEADER 파싱
    • 우선순위: 높음
    • 상태: 조사 중

    #버전 관리

    • 0.1.0-rc.1: 초기 배포 시작