이 폴더의 자바스크립트 라이브러리는 오픈소스이며 상업적 이용이 허용됩니다. 1) pdf-lib.min.js - 프로젝트: pdf-lib (https://github.com/Hopding/pdf-lib) - 라이선스: MIT - 전문: pdf-lib.LICENSE.txt 2) pdf.min.mjs / pdf.worker.min.mjs - 프로젝트: PDF.js (Mozilla, https://github.com/mozilla/pdf.js) - 라이선스: Apache License 2.0 - 전문: pdfjs.LICENSE.txt 3) mediapipe/ 폴더 - 프로젝트: MediaPipe Tasks Vision (Google) - 라이선스: Apache License 2.0 - 전문: mediapipe/LICENSE.txt - 용도: 증명사진 도구의 AI 배경 제거 (브라우저 내 추론) - 모델: selfie_multiclass_256x256.tflite (16MB) 를 우선 사용합니다. 배경/머리카락/피부/옷 등을 따로 구분해 정확도가 높습니다. 불러오지 못하면 selfie_segmenter.tflite (250KB) 로 대체됩니다. 모든 라이선스가 저작권 고지를 함께 배포할 것을 요구하므로 LICENSE 파일들을 삭제하지 말고 그대로 두세요. [용량 참고] mediapipe/wasm/vision_wasm_module_internal.js 와 .wasm 은 실제 로딩에 사용되지 않는 변형입니다. 지우면 약 12MB를 아낄 수 있고 동작에는 영향이 없습니다 (SIMD판과 비SIMD판만 있으면 됩니다). 4) upscaler/ 폴더 — 사진 화질 개선(AI 업스케일) 도구 - tf.min.js : TensorFlow.js 4.22 (Google) — Apache License 2.0, 전문: upscaler/tfjs.LICENSE.txt - upscaler.min.js : UpscalerJS 1.0 (Kevin Scott) — MIT, 전문: upscaler/upscalerjs.LICENSE.txt - esrgan-medium-x2/x4 : @upscalerjs/esrgan-medium 모델 정의 + 가중치(models/x2, models/x4) — MIT, 전문: upscaler/esrgan-medium.LICENSE.txt - 모든 추론은 브라우저 안에서 실행되며 모델 파일은 이 폴더에서만 불러옵니다(CDN 사용 안 함). 5) ocr/ 폴더 — 사진 글자 추출(OCR) 도구 - tesseract.min.js / worker.min.js : Tesseract.js 7.0.0 — Apache License 2.0, 전문: ocr/tesseractjs.LICENSE.txt - tesseract-core-simd-lstm.js + .wasm (SIMD 지원 기기용, 기본) tesseract-core-lstm.js + .wasm (비SIMD 폴백) : tesseract.js-core 7.0.0 (Tesseract OCR 엔진의 WebAssembly 빌드, LSTM 전용) — Apache License 2.0, 전문: ocr/tesseractjs-core.LICENSE.txt : 페이지가 WebAssembly SIMD 지원 여부를 직접 확인해 둘 중 하나를 고릅니다. - (단일파일 판 tesseract-core-*-lstm.wasm.js 는 용량 때문에 넣지 않았습니다. 글루 .js + 별도 .wasm 조합만 배포하며, 페이지의 2순위 폴백 시도는 404 로 끝나고 그 경우 안내 문구만 표시됩니다.) - lang/kor.traineddata.gz (약 1.06MB), lang/eng.traineddata.gz (약 1.88MB) : Tesseract 공식 언어 데이터 tessdata_fast — Apache License 2.0, 전문: ocr/tessdata.LICENSE.txt : tesseract.js 는 langPath 아래에서 <언어코드>.traineddata.gz 를 찾습니다 (gzip:true 옵션). 파일 이름을 바꾸지 마세요. - 인식은 전부 브라우저 안에서 실행되며, createWorker 의 workerPath·corePath·langPath 를 모두 /tools/lib/ocr/ 절대경로로 지정하고 workerBlobURL:false 로 두어 CDN 등 외부 요청이 전혀 없습니다. 6) faceapi/ 폴더 — 사진 얼굴 자동 모자이크 도구 - dist/face-api.js : @vladmandic/face-api 1.7.15 (Vladimir Mandic) — MIT, 전문: faceapi/faceapi.LICENSE.txt : 이 한 파일 안에 TensorFlow.js 런타임이 함께 번들되어 있습니다 (TensorFlow.js — Apache License 2.0, 전문: faceapi/tfjs.LICENSE.txt). 그래서 tf.min.js 를 따로 넣지 않습니다. - model/ssd_mobilenetv1_model-weights_manifest.json + ssd_mobilenetv1_model.bin (약 5.6MB) : 기본(정확) 얼굴 검출기. SSD MobileNet v1 기반. - model/tiny_face_detector_model-weights_manifest.json + tiny_face_detector_model.bin (약 190KB) : "빠르게(작은 모델)" 옵션용 경량 검출기. - 가중치 매니페스트가 .bin 파일을 같은 폴더에서 상대 이름으로 찾으므로 manifest 와 .bin 을 반드시 같은 폴더에 두고 이름을 바꾸지 마세요. 페이지는 loadFromUri('/tools/lib/faceapi/model') 절대경로로만 모델을 불러옵니다. - face-api 번들에는 tfjs 의 wasm 백엔드도 들어 있는데, 그 백엔드는 .wasm 파일을 기본적으로 CDN 에서 찾습니다. 그래서 페이지가 시작할 때 wasm 백엔드를 제거하고 webgl → cpu 순서로 백엔드를 고정합니다. 외부 요청은 전혀 발생하지 않습니다. - 얼굴 검출·모자이크 처리는 모두 브라우저 안에서 실행되며 사진은 전송되지 않습니다. - (얼굴 랜드마크·표정·나이·인물 대조용 모델은 이 도구에 필요 없어서 넣지 않았습니다.) 7) pdfocr/ 폴더 — PDF 글자 추출(OCR) 도구의 "검색 가능한 PDF" 저장용 - fontkit.umd.min.js : @pdf-lib/fontkit 1.1.1 (Devon Govett 외) — MIT, 전문: pdfocr/fontkit.LICENSE.txt : pdf-lib 이 TrueType/OpenType 글꼴을 읽고 서브셋으로 잘라 PDF 에 넣으려면 이 모듈이 필요합니다. 페이지는 PDFLib.PDFDocument.registerFontkit(fontkit) 로 등록한 뒤 embedFont(bytes,{subset:true}) 를 씁니다. - NanumGothic-Regular.ttf (약 2.0MB) : 나눔고딕 Regular (네이버) — SIL Open Font License 1.1, 전문: pdfocr/NanumGothic.OFL.txt : 스캔 PDF 위에 얹는 "보이지 않는 글자 층"(텍스트 렌더링 모드 3, Invisible)에 쓰이는 글꼴입니다. 화면에는 나타나지 않고 검색·복사·화면낭독기용 글자 코드만 담습니다. PDF 안에는 문서에 실제로 등장한 글자만 골라낸 서브셋(보통 수십 KB)이 들어가며, 2MB 원본 전체가 들어가지 않습니다. : OFL 은 글꼴을 문서에 포함(embedding)해 배포하는 것을 명시적으로 허용하며, 상업적 이용도 허용합니다. OFL 의 판매 금지 조항은 글꼴 파일 자체를 단독으로 파는 경우에만 해당하므로, 글꼴이 포함된 PDF 를 만들고 배포하는 데는 제한이 없습니다. 예약된 글꼴 이름(Reserved Font Name)을 바꾸지 않도록 파일 이름과 내부 이름을 그대로 두세요. - 이 두 파일은 사용자가 "검색 가능한 PDF 저장"을 처음 누를 때만 내려받습니다. 텍스트만 뽑아 쓰는 경우에는 전혀 불러오지 않습니다. - 함께 쓰이는 pdf-lib.min.js(1번)와 pdf.min.mjs(2번)도 모두 이 폴더에서만 불러오며, 외부 CDN 요청은 전혀 발생하지 않습니다. 8) hwp/ 폴더 — HWP·HWPX 뷰어 도구 [한컴 공개 규격 고지] 본 도구(8·9절)는 한글과컴퓨터의 한글 문서 파일(.hwp) 공개 문서를 참고하여 개발된 rhwp 엔진을 사용합니다. 한컴 공개 규격의 이용 조건(2011.1.24 개정)에 따라 이 고지를 소스(README)와 도구 화면(뷰어·편집기 페이지 푸터)에 표기합니다. 한글·한컴은 (주)한글과컴퓨터의 상표입니다. - rhwp.js + rhwp_bg.wasm (약 10MB) : rhwp / @rhwp/core 0.8.6 — MIT, 전문: hwp/rhwp.LICENSE.txt : 한글(아래아한글) 문서를 읽고 조판해 페이지마다 SVG 로 그려 주는 Rust + WebAssembly 라이브러리입니다. HWP 5 이진 형식과 HWPX(개방형 XML)를 모두 읽고, HWP 3.0 / HWPML 은 부분적으로 지원합니다. : 페이지는 `import init,{HwpDocument,version} from '/tools/lib/hwp/rhwp.js'` 로 불러온 뒤 `await init({module_or_path:'/tools/lib/hwp/rhwp_bg.wasm'})` 로 시작합니다. .wasm 은 진행률을 보여 주려고 fetch 로 먼저 받아 바이트로 넘깁니다. : init 을 부르기 전에 `globalThis.measureTextWidth = (font, text) => …` 를 반드시 등록해야 합니다. 줄바꿈 위치를 정하려면 글자 폭이 필요한데 그 값은 브라우저(캔버스 measureText)만 알기 때문입니다. 등록하지 않으면 조판이 틀어집니다. : 쓰는 API 는 `new HwpDocument(bytes)`(암호 문서는 `HwpDocument.openWithPassword(bytes, pw)`), `pageCount()`, `getPageInfo(i)`(용지 크기·여백 JSON), `renderPageSvg(i)`(완전한 문자열), `getTextFileUnicode()`(문서 전체 텍스트, JSON 문자열이라 JSON.parse 필요), `exportHwpx()` / `exportHwp()`(Uint8Array), 그리고 다 쓴 뒤 `free()` 입니다. : 주의 — `new HwpViewer(doc)` 를 만들면 doc 의 소유권이 뷰어로 넘어가서 이후 doc 메서드를 부르면 "null pointer passed to rust" 로 죽습니다. 이 도구는 HwpViewer 를 쓰지 않습니다. : renderPageSvg 는 위치를 정확히 맞추려고 글자를 한 자씩 따로 로 냅니다. 그대로 두면 브라우저 선택·복사와 Ctrl+F 가 되지 않으므로, 페이지가 화면에 올리기 직전 같은 줄의 글자들을 하나의 + 으로 합치고 각 글자의 x 를 그대로 나열합니다(보이는 위치는 전혀 바뀌지 않습니다). - NanumMyeongjo-Regular.ttf (약 3.0MB) : 나눔명조 Regular (네이버) — SIL Open Font License 1.1, 전문: hwp/NanumMyeongjo.OFL.txt : 한글 문서는 글꼴을 이름으로만 가리키므로(함초롬바탕·한컴바탕·휴먼명조·HY 계열 등) 그 글꼴이 없는 기기에서는 대체가 필요합니다. 바탕·명조 계열 이름을 @font-face 로 이 파일에 연결합니다. 돋움·고딕 계열은 7) pdfocr/ 의 NanumGothic-Regular.ttf 를 그대로 참조합니다(복사본을 만들지 않습니다). : @font-face 의 src 는 `local('원래 이름'), url('…ttf')` 순서라, 기기에 진짜 글꼴이 있으면 그것을 쓰고 없을 때만 나눔 글꼴을 내려받습니다. 그래서 한컴오피스가 깔린 윈도우에서는 추가 다운로드가 거의 일어나지 않습니다. - PDF 로 묶을 때는 1) 의 pdf-lib.min.js 를 씁니다. 외부 CDN 요청은 전혀 없습니다. 9) hwp/editor + hwp/studio — HWP·HWPX 편집기 도구 (/tools/hwp-editor/) - hwp/editor/ (index.js, transport.js, document-agent-contract.js) : @rhwp/editor 0.8.6 (Edward Kim) — MIT, 전문: hwp/editor/LICENSE.txt : iframe 으로 올린 rhwp-studio 와 postMessage 로 대화하는 얇은 ES 모듈입니다. 페이지는 `import {createEditor} from '/tools/lib/hwp/editor/index.js'` 뒤 `createEditor('#editor',{studioUrl:'/tools/lib/hwp/studio/',renderer:'canvas2d'})` 로 만들고, `loadFile(bytes,name)`, `pageCount()`, `exportHwpx()`, `exportHwp()`, `getDocumentState()`(changeSeq 로 수정 여부 감시), `commands.execute('file:new-doc')`, `notifySaved(name)` 을 씁니다. : 주의 — iframe 을 DOM 안에서 다른 곳으로 옮기면 studio 가 다시 로드되어 편집 상태가 사라집니다. display:none 은 괜찮습니다. 편집기는 페이지 진입 시 만들지 않고 사용자가 파일을 넣거나 "빈 문서로 시작"을 눌렀을 때 한 번만 만듭니다. : 암호 문서는 studio 가 iframe 안에 비밀번호 창을 띄우고 사람이 입력할 때까지 loadFile 이 기다리므로 requestTimeoutMs 를 길게(15분) 잡았습니다. - hwp/studio/ (index.html, assets/, fonts/, icons/, images/, rhwp.js, theme-init.js …, 약 39MB) : rhwp-studio 0.8.6 (Edward Kim) 셀프 호스팅 빌드 — MIT, 전문: hwp/studio/LICENSE.txt : 메뉴·도구 모음·표·글자 모양·머리말/각주·찾기가 들어 있는 완전한 편집기 UI 입니다. 외부 웹폰트를 쓰지 않도록 RHWP_DISABLE_EXTERNAL_WEBFONTS=1 로 빌드했고, 실행 중 외부 호스트 요청이 0 임을 확인했습니다. 원본 배포본의 PWA 서비스워커와 샘플 문서는 제거했습니다. : assets/ 의 rhwp_bg-*.wasm(약 10MB) 과 index-*.js 가 편집 엔진이고, canvaskit-*.wasm 은 renderer=canvaskit 일 때만 받습니다(이 도구는 canvas2d). : fonts/ 의 동봉 글꼴은 전부 SIL Open Font License 1.1 입니다 — 나눔고딕·나눔명조·나눔고딕코딩(네이버), Noto Sans KR·Noto Serif KR(구글), Pretendard(길형진), 고운바탕·고운돋움(윤민구), D2Coding(네이버), 스포카 한 산스(스포카), Source Han Serif K 옛한글 subset(어도비, 전문: hwp/studio/fonts/SourceHanSerifK-OFL.txt). 목록과 출처는 hwp/studio/fonts/FONTS.md 에 있습니다. 한컴·마이크로소프트 글꼴은 포함하지 않았고 위 OFL 글꼴로 대체됩니다. : studio 는 창 하나로 열렸을 때만 첫 실행 "화면 스킨 선택" 창을 띄우고, iframe 안(window.parent!==window)에서는 띄우지 않습니다. 스킨·테마는 보기 메뉴(view:skin-*, view:theme-*)로 바꾸며 localStorage 에 남습니다. - 8) 의 rhwp.js + rhwp_bg.wasm(@rhwp/core) 와는 별개 사본이며, 뷰어(/tools/hwp/)는 그대로 8) 을 씁니다. 외부 CDN 요청은 전혀 없습니다. 10) video/ 폴더 — 동영상 용량 줄이기 도구 (/tools/video-compress/) - mp4box.all.mjs + styp-9TIZZDLN.mjs + rolldown-runtime-w6R9maHv.mjs : mp4box.js 2.4.1 (Cyril Concolato / GPAC) — BSD-3-Clause, 전문: video/mp4box.LICENSE.txt : MP4/MOV 컨테이너를 읽는(디먹스) ES 모듈입니다. mp4box.all.mjs 가 나머지 두 청크를 상대 경로로 import 하므로 세 파일을 반드시 같은 폴더에 두고 이름을 바꾸지 마세요. : 페이지는 `import * as MP4Box from '/tools/lib/video/mp4box.all.mjs'` 뒤 `createFile()`(mdat 데이터는 버리고 메타만 유지) 에 파일을 4MB 씩 `appendBuffer` (buffer.fileStart 지정, 반환값이 다음 읽을 위치 — moov 가 뒤에 있으면 그리로 건너뜀) 하여 `onReady(info)` 를 받고, `getTrackSamplesInfo(id)` 의 샘플 표(offset/size/cts/dts) 로 파일에서 직접 8MB 창 단위로 샘플을 읽습니다(onSamples 는 쓰지 않음). : 코덱 설명(avcC/hvcC)은 stsd entry 의 박스를 DataStream 으로 write 한 뒤 8바이트 헤더를 뗀 것이고, AAC 의 AudioSpecificConfig 는 esds.esd 의 DecoderConfigDescriptor(태그 4) 안 DecoderSpecificInfo(태그 5).data 입니다. 회전은 tkhd matrix 에서 읽습니다. - mp4-muxer.mjs : mp4-muxer 5.2.2 (Vanilagy) — MIT, 전문: video/mp4-muxer.LICENSE.txt : 인코딩된 청크를 MP4 로 묶는(먹스) ES 모듈입니다. video {codec:'avc'|'vp9', rotation}, audio {codec:'aac'|'opus'} 로 만들고 addVideoChunk / addAudioChunkRaw(원본 오디오 그대로 복사) 뒤 finalize() 합니다. 기본은 ArrayBufferTarget + fastStart:'in-memory', 결과가 300MB 를 넘고 showSaveFilePicker 가 있으면 FileSystemWritableFileStreamTarget 로 디스크에 바로 씁니다. - 두 라이브러리는 디먹스·먹스만 담당하며, 영상 디코드·인코드는 브라우저 WebCodecs (VideoDecoder/VideoEncoder — OS·GPU 내장 코덱)가 합니다. ffmpeg 계열(LGPL)은 쓰지 않습니다. 외부 CDN 요청은 전혀 없고 영상은 전송되지 않습니다.