소개
시작하기
npm 패키지 설치부터 뷰어 배포와 첫 저장 API 연결까지 적용하는 절차입니다. 소스와 배포 조건은 GitHub 저장소의 Apache-2.0 LICENSE에서 확인할 수 있습니다.
사전 준비
- Node.js와 npm —
inko-pdf-sdk패키지를 설치하는 데 사용합니다. - 정적 파일을 서빙할 수 있는 웹 서버 — Nginx·Apache·Tomcat·IIS 등 무엇이든 가능합니다.
npm은 검증된 정적 산출물을 받는 설치 경로입니다. 실행 시 별도 서버 모듈이나 번들러 없이 정적 파일과 <script>로 로드할 수 있습니다. 호스트 앱의 저장 API·인증·권한·보안 정책은 별도로 구현하고 검증해야 합니다.
1단계 — npm 패키지 설치
npm install inko-pdf-sdk설치된 패키지의 viewer/에는 뷰어 본체가, sdk/inko-sdk.js에는 호스트 페이지용 래퍼가 들어 있습니다.
npm 패키지는 래퍼를 sdk/inko-sdk.js로 제공합니다.
NextH의 self-hosted 데모는 같은 공개 API 번들을 기존 산출물 이름인 /pdfv/sdk/pdfv-sdk.js에서 제공합니다. 실제 배포한 파일명에 맞춰 script src를 지정하세요.
두 번들 모두 window.Inko만 등록합니다.
2단계 — 뷰어 배포
node_modules/inko-pdf-sdk/viewer/의 내용과 node_modules/inko-pdf-sdk/sdk/inko-sdk.js를
이용자 서버 /pdfv/ 경로에 위 구조대로 배치합니다.
host-server/
└─ pdfv/ ← 이용자 서버에서 직접 제공하는 정적 자산
├─ index.html ← 뷰어 본체 (iframe으로 로드됨)
├─ assets/ ← 뷰어 JS·CSS 번들
└─ sdk/
└─ inko-sdk.js ← 호스트 페이지에서 로드하는 SDK 래퍼뷰어를 호스트 페이지와 같은 도메인의 하위 경로(예: https://erp.example.com/pdfv/)에 두면
뷰어와 호스트 사이의 origin 구성이 단순해집니다.
별도 도메인 배포는 CSP·frame-ancestors·PDF CORS를 구성하고 도입 환경에서 호환성을 검증해야 합니다.
3단계 — SDK 로드
PDF를 띄울 페이지에서 SDK 스크립트를 로드합니다. 브라우저 전역 객체 window.Inko가 등록됩니다.
<!-- npm의 sdk/inko-sdk.js를 아래 URL로 배포한 예 -->
<script src="/pdfv/sdk/inko-sdk.js"></script>4단계 — 마운트
컨테이너 요소를 두고 Inko.mount()를 호출하면, 컨테이너 안에 뷰어 iframe이 생성되고 PDF가 로드됩니다.
<div id="pdf-container" style="width:100%; height:80vh"></div>
<script>
var viewer = Inko.mount('#pdf-container', {
src: '/pdfv/index.html', // 뷰어 본체 URL (필수)
pdfUrl: '/files/document.pdf', // 표시할 PDF
fileName: 'document.pdf'
});
</script>src는 1단계에서 배포한 뷰어 본체의 URL입니다. 컨테이너의 크기가 곧 뷰어의 크기이므로,
컨테이너에 명시적인 높이를 지정해야 합니다.
전체 예제 — 저장까지
실제 운영에서는 저장 콜백(onSave)으로 받은 canvasData를 자체 DB에 적재합니다.
아래는 저장·이어서 편집·에러 처리까지 포함한 전체 흐름입니다.
<div id="pdf-container" style="width:100%; height:80vh"></div>
<script src="/pdfv/sdk/inko-sdk.js"></script>
<script>
var viewer = Inko.mount('#pdf-container', {
src: '/pdfv/index.html',
pdfUrl: '/files/contract.pdf',
fileName: 'contract.pdf',
// 직전에 저장해 둔 버전이 있으면 그 지점부터 이어서 편집.
// SAVED_CANVAS_DATA는 예시용 이름 — 호스트 서버가 페이지에 심어 주는 값입니다 (없으면 undefined)
initialCanvasData: window.SAVED_CANVAS_DATA || undefined,
onReady: function () {
console.log('뷰어 준비 완료');
},
onSave: async function (canvasData, ok, msg) {
if (!ok) { alert('저장 실패: ' + msg); return; }
// ok는 SDK 직렬화 성공. 호스트 DB 저장 성공은 API 응답으로 확인합니다.
var response = await fetch('/api/annotations', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ documentId: 'contract-123', baseVersion: 7, canvasData: canvasData })
});
if (!response.ok) throw new Error('저장 API 실패');
},
onError: function (err) {
console.error('[Inko]', err);
}
});
// 외부 버튼에서 저장 트리거도 가능
// document.querySelector('#save-btn').onclick = function () { viewer.save(); };
</script>save()/onSave는 펜·형광펜·텍스트·도형을 다시 편집할 수 있는 canvasData 문자열을 다룹니다. await viewer.exportPdf()는 지원하는 네이티브 AcroForm의 현재 값을 반영한 ArrayBuffer를 반환하지만
Inko 드로잉은 PDF에 합성하지 않습니다. 두 결과가 필요하면 호스트 저장소에 각각 보관하세요.
window.SAVED_CANVAS_DATA·/api/annotations·docId: 123처럼
예제에 등장하는 변수·API 경로·ID는 설명용 이름입니다. 호스트 앱의 실제 변수와
엔드포인트로 바꿔 사용하세요. 이 규칙은 모든 문서의 예제에 동일하게 적용됩니다.
동작 확인 체크리스트
| 확인 항목 | 기대 동작 |
|---|---|
| 페이지 접속 | 컨테이너 영역에 뷰어 툴바와 PDF 첫 페이지가 표시됩니다. |
| 펜으로 드로잉 | PDF 위에 필기가 그려지고 onChange 콜백이 호출됩니다. |
contentSelect 내용 선택 | Text Layer가 있는 PDF에서 원문 텍스트를 선택·복사할 수 있습니다. 이미지 PDF에 OCR을 추가하지는 않습니다. |
| 검색·책갈피 | 검색은 가상화된 전체 페이지의 Unicode 리터럴을 찾고, 책갈피는 내장 outline이 있는 문서에서만 표시됩니다. |
| 저장 버튼 클릭 | onSave 콜백에 canvasData 문자열이 전달됩니다. |
exportPdf() | 지원하는 네이티브 AcroForm 값이 반영된 PDF ArrayBuffer가 반환되며, canvasData 드로잉은 포함되지 않습니다. |
저장 후 재접속 + initialCanvasData 주입 | 직전 작업이 복원된 상태로 열립니다. |
여기까지 확인되면 통합이 완료된 것입니다. 다음 단계로 저장과 버전 관리에서 버전 테이블 설계를, 커스터마이징에서 브랜드 적용 방법을 확인하세요. 진행 중 막히는 부분이 있으면 FAQ · 트러블슈팅에서 증상별 해결 방법을 찾아보세요.