PDF.js を利用したシンプルな PDF ビューワ

PDF.js を使ったシンプルな PDF ビューワのメモ。

# PDF.js
PDF.js を使うと Web ページに PDF を表示することができます。
PDF.js は以下からダウンロードできます。
https://mozilla.github.io/pdf.js/

# シンプル PDF ビューワ
PDF.js で PDF を表示するには、ある程度プログラムする必要があるため、比較的単純に使えるようにライブラリ化してみました。

以下で Web サーバ上の path_to_pdf.pdf を表示します。
```javascript:
import * as pdfjsLib from './pdfjs/build/pdf.mjs';
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs/build/pdf.worker.mjs';
import { SimplePdfViewer } from './simple_pdf_viewer.mjs';

const pdf_viewer = new SimplePdfViewer(pdf_params);
pdf_viewer.render_url('path_to_pdf.pdf');
```

input type="file" でアップロードされたファイルも表示できます。
```javascript:
import * as pdfjsLib from './pdfjs/build/pdf.mjs';
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs/build/pdf.worker.mjs';
import { SimplePdfViewer } from './simple_pdf_viewer.mjs';

const pdf_viewer = new SimplePdfViewer(pdf_params);
pdf_viewer.render_file('id_file');
```

SimplePdfViewer のプログラムはこちら。
```javascript:simple_pdf_viewer.mjs
// caller needs to import pdf.js
// import * as pdfjsLib from './pdfjs/build/pdf.mjs';
// pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs/build/pdf.worker.mjs';


export class SimplePdfViewer {
  constructor(params) {
    this.params = params;

    this.pdf = null;
    this.canvas = document.getElementById(this.params.id_canvas);
    this.canvas_context = this.canvas.getContext('2d');
    this.scale = params.scale ? params.scale : 1.0;
    this.page_num = params.page_num ? params.page_num : 1;

    this.page_num_pending = null;

    this.id_button_prev = this.params.id_button_prev;
    if (this.id_button_prev && document.getElementById(this.id_button_prev)) {
      document.getElementById(this.id_button_prev).addEventListener('click', (e) => { this.to_prev_page(); });
    }
    
    this.id_button_next = this.params.id_button_next;
    if (this.id_button_next && document.getElementById(this.id_button_next)) {
      document.getElementById(this.id_button_next).addEventListener('click', (e) => { this.to_next_page(); });
    }

    this.id_text_page_num = this.params.id_text_page_num;
  }

  // render uploaded file
  render_file(id_file) {
    document.getElementById(id_file).addEventListener('change', (e) => {
      const reader = new FileReader();
      reader.onload = (e) => {
        const content = new Uint8Array(e.target.result);
        pdfjsLib.getDocument(content).promise.then((pdf) => {
          this.pdf = pdf;
          this.render_page(1);
        })
      };

      const file = e.target.files[0];
      reader.readAsArrayBuffer(file);
    });
  }


  render_page(page_num) {
    this.page_num = page_num;

    this.pdf.getPage(page_num).then((page) => {
      this.viewport = page.getViewport({scale: this.scale});
      this.canvas.height = this.viewport.height;
      this.canvas.width = this.viewport.width;

      const render_context = {
        canvasContext: this.canvas_context,
        viewport: this.viewport
      };

      page.render(render_context);
    });

    if (this.id_text_page_num && document.getElementById(this.id_text_page_num))
      document.getElementById(this.id_text_page_num).textContent = this.page_num;
  }


  to_prev_page() {
    if (this.page_num <= 1) return;
    this.render_page(this.page_num-1);
  }


  to_next_page() {
    if (this.page_num >= this.pdf.numPages) return;
    this.render_page(this.page_num+1);
  }
}
```

html はこちら。
```javascript:simple_pdf_viewer.html
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>simple pdf viewer</title>
  </head>
  <body>
    <!-- ファイル選択 -->
    <div>
      <input id="id_pdf_file" type="file" accept="pdf" />
    </div>

    <!-- ページ移動 -->
    <div style="display: flex;">
      <input id="id_pdf_prev" type="button" value="&lt;" />
      <p id="id_pdf_page_num"> </p>
      <input id="id_pdf_next" type="button" value="&gt;" />
    </div>

    <!-- PDF 描画 -->
    <div style="border: solid 1px;">
      <canvas id="id_pdf_canvas"></canvas>
    </div>
  </body>
  <script type="module">
import * as pdfjsLib from './pdfjs/build/pdf.mjs';
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs/build/pdf.worker.mjs';

import { SimplePdfViewer } from './simple_pdf_viewer.mjs';


function main() {
  const pdf_params = {
    id_canvas: 'id_pdf_canvas',
    id_file: 'id_pdf_file',
    id_button_prev: 'id_pdf_prev',
    id_button_next: 'id_pdf_next',
    id_text_page_num: 'id_pdf_page_num',
    scale: 0.75,
  };

  const pdf_viewer = new SimplePdfViewer(pdf_params);
  pdf_viewer.render_file(pdf_params.id_file);
  //pdf_viewer.render_url('test1.pdf');
}

main();
  </script>
</html>
```