WEB에서 PDF VIEWER 사용하기

WEB, IFRAME, PDF, pdf.js

Posted by iheese on July 26, 2024 · 8 mins read

개요

  • 업무 중 pdf 파일을 불러와 웹에서 보여줘야 할 일이 생겼다.
  • 기존에는 pdf 파일을 html 파일로 직접 작성하여 일일히 보여주고 있었다. 아니면 파일을 다운로드해서 보는 방식으로 구현되어 있었다.
    • pdf 파일의 변경 빈도가 꽤 잦았기 때문에 효율성이 매우 떨어졌다.


요구사항

  • 다운로드 방식이 아닌 웹 내에서 pdf를 확인할 수 있어야 함.
  • *pdf 파일을 제어할 수 있어야 함.
    • 스크롤, 페이지별로 이동, 줌 제어 등등
  • 크롬, 엣지에서 pdf 파일을 잘 보여줄 수 있어야 함. (다른 브라우저는 지원하지 않음)


분석

  • pdf 파일을 웹 상에서 열면 embed 태그를 이용해 viewer가 열린다. Adobe Acrobat Document 가 웹 상에서도 열리는 것을 지원하기 때문인 것 같다.
    • 줌, 페이지 이동, 인쇄 등 다양한 기능이 제공된다.
  • but 검색 결과 내부 pdf 파일을 제어할 수 없을 것으로 판단하여 다른 방법을 찾게 된다.



결론 : pdf.js 를 사용하자


이유

  1. embed와 마찬가지로 iframe 태그만으로는 제어가 불가능함.
  2. PDFObject 를 사용하는 것도 결국에는 내부적으로 embed 로 pdf파일을 불러오는 형태여서 제어가 불가능했음.
  3. pdf.js는 pdf 파일을 읽어 html 태그로 만들어주기 때문에 제어가 가능하였다.
    • 또한 실제 html나 jsp 파일에는 iframe 한 줄만 넣으면 되기 때문에 간단하게 pdf viewer를 사용할 수 있었다.


개발 과정

  • HTML, JavaScript를 이용한 프로젝트 기준으로 설명될 예정입니다.


준비

  • 해당 깃헙에서 파일을 다운로드하고 압축 풀어서 프로젝트의 정적 파일이 모이는 곳인 myProject/WebContent 아래 pdf.js 모듈을 넣는다.
  • pdf.js 폴더에는 web, build 가 있고, web 아래 보여주고 싶은 pdf 파일을 넣는다.
  • 준비 끝!


코드 작성

HTML 코드

<iframe id="myPDF" scr="/pdfjs/web/viewer.html?file=files/myPDF.pdf"></iframe>
  • 내 pdf 파일의 위치는 web 아래 files/myPDF.pdf
  • pdf viewer를 넣고 싶은 곳에 위에 태그를 넣어준다.

  • pdf.js 오픈소스 wiki 에 나온 것처럼 #page=2&zoom=200 을 붙여서 pdf 를 보여줄 수 있다.
  • 옵션 : [zoom], [left offset], [top offset], page-width, page-height, page-fit, auto
<iframe id="myPDF" scr="/pdfjs/web/viewer.html?file=files/myPDF.pdf#zoom=50&page=3"></iframe>
  • pdf 파일을 50배의 줌 상태로 3페이지를 보여줘 라는 뜻이다.
  • 자세한 내용을 위키를 뒤적여보자.


  • 또한 iframe의 태그 옵션을 이용해서 변환할 수 있다.

  • iframe 태그 옵션들
  • 자세한 건 위에서 찾아보자
<iframe id="myPDF" scr="/pdfjs/web/viewer.html?file=files/myPDF.pdf#zoom=50&page=3" width="500px" height="1000px"></iframe>
  • width, height 옵션을 이용해 보여지는 viewer 크기를 조절했다.
  • style 옵션을 줘서 css를 수정하거나, id 값을 부여했으니 css 파일을 불러와서 적용해도 좋다.


Javascript 코드

  • 해당 pdf 파일을 제어하기 전 pdfjs의 pdf를 보여주는 /web/viewer.html 를 확인해보자
  • 내부적으로 코드를 수정해서 보여주고 싶은 곳만 보여줄 수 있다.
    • 참고로 class 에 hidden 을 추가해주면 숨길 수 있다.
  • 개발을 진행할 때는 웹에서 F12 눌러서 태그나 id값을 보면서 개발하면 된다.


꼭 알아야 하는 점

  • 코드를 보면 기존 html 위에 iframe이 뜨게 되고 그 안에 #document 가 생성되게 된다.
  • 그럼 접근을 어떻게 해야할까?

contentWindow 를 이용하자

  • “contentWindow” property 는 iframe 내 윈도우 객체에 접근할 수 있는 방법이다.
var pdfView = document.getElementById("myPDF").contentWindow.document;
console.log(pdfView.getElementById("viewerContainer"));
  • pdfView는 iframe 내부 document 에 접근한 상태이고, 이를 통해 viewer.html의 태그에 접근할 수 있게 된다.
  • 위 예시에서 콘솔에 찍은 것은 내부에서 사용하는 viewerContainer 이다. 사용하시면 많이 접근하시게 될 것이다.


추가 사항

유용하게 사용했던 팁

var pdfView = document.getElementById("myPDF").contentWindow.document;
var maxValue = pdfView.getElementById("pageNumber").getAttribute("max");
console.log(maxValue);
  • 불러온 pdf 파일의 최대 페이지 수를 구하고 싶을 때 사용했던 방법이다.


주의 사항 경험담

  • 네트워크 상황에 따라 pdf 불러오는 것이 지연될 가능성이 있다. 특히 처음 pdf 를 불러오면 직접 서버에서 받아와야 하기 때문에 시간이 오래 걸릴 수 있다.
  • 근데 JS 파일에 contentWindowd를 이용해 태그에 접근해 제어하게 되면 console에 수많은 에러를 찍게 되고 원하는 대로 동작하지 않을 가능성이 농후하다.
  • 나의 작고 소중한 2가지 해결 방법을 공유하자면..

시간두기

var maxValue;
const pdfView = document.getElementById("myPDF").contentWindow.document;

setTimeout(() => {
    maxValue = pdfView.getElementById("pageNumber").getAttribute("max");
}, 3000);

console.log(maxValue);
  • 뭐야 하겠지만 꽤 유용하게 사용했다. 일부러 시간을 두어서 pdf 파일이 모두 로드되는 시간을 충분히 주고 내부 contentWindow에 접근하는 방식이다.
  • pdf 파일이 뿅하고 나타나면서 특정 js 행위를 할 때? 사용했다.
    • 최대 로드 시간을 추측해야하는 큰 단점이 있다. 비추이긴 하다^^


상태 확인

  • contentWindow.document 도 document 이라는 것을 잊지말자.
  • document는 loading, interactive, complete 순서로 readyState 상태가 변한다.
    • loading : 로딩 중
    • interactive : 로딩은 끝이지만 images, stylesheets, frames과 같은 하위 자원들은 로딩되고 있는 상태                   
    • complete : 하위 자원까지 로딩 완료, 이 상태는 load 이벤트가 발생되기 직전 상태
var maxValue;
const pdfView = document.getElementById("myPDF").contentWindow.document;
if(pdfView.readyState == "complete") {
    maxValue = pdfView.getElementById("pageNumber").getAttribute("max");
}
  • 상태를 확인 후 iframe 내부 document에 접근하는 방식이다.
  • 더 확실하게 한다면? 재귀함수를 만들어서 사용해보자


function checkLoadDocument(pdfView) {
    if(pdfView.readyState == "complete") {
        maxValue = pdfView.getElementById("pageNumber").getAttribute("max");
    } else {
        setTimeout(checkLoadDocument(pdfView), 1000);
    }
}
  • 재귀적으로 1초마다 확인하여 변수값을 넣어주는 함수이다.


결론

  • 열심히 코드를 고쳐가며 찾은 나의 경험이다. 덕분에 pdf 파일을 제어하면서 깔끔하게 보여줄 수 있었다.
  • 나의 경험이 누군가에게 도움이 되길 기원한다.

Reference: