PDF.jsを設置する


PDF.jsはJavaScriptで作られたPDFビューアです。(厳密にはPDF読み込みを行うパーサ、描画を行うレンダラ、画面UIのビューアがセットになっているもので、ライセンスはApache License 2.0です)

- Mozilla Foundationが開発していてFirefoxのPDFビューアとして採用されているため品質が高い
- JavaScriptでPDFを読み込んでCanvasで描画しているためiPhoneやAndroidなどスマートフォンでも表示できる
- ビューアがHTMLファイルのため&lt;iframe&gt;でPDFを埋め込み表示できる

のような特長があり、PDFを直接表示できない環境での代替として使用することがよくあります。

この文書では、PDF.jsの基本的な設置方法を説明します。

## 1. 配布サイトからファイルをダウンロードする

まず https://mozilla.github.io/pdf.js/getting_started/#download にある「Stable (v1.4.20)」ボタンをクリックしてファイルをダウンロードしてください。

![image](https://qiita-image-store.s3.amazonaws.com/0/782/37c68aee-ed73-a4f4-b1e5-1f68add0be09.png)

## 2. 設置する

1でダウンロードしたpdfjs-1.4.20-dist.zipを解凍してサーバ上に配置してください。
ローカル環境のドキュメントルートフォルダの直下に配置した場合は http://localhost/pdfjs-1.4.20-dist/web/viewer.html にアクセスするとページが表示されます。(フォルダ名などを変えるのは自由です)

![image](https://qiita-image-store.s3.amazonaws.com/0/782/2c59c811-33a6-7247-8ed3-7992c25d6208.png)

初期状態ではpdfjsのwebフォルダにある compressed.tracemonkey-pldi-09.pdf が表示されます。

※ 必ずサーバ上で表示させてください。普通にファイルで開いても表示されません。(アドレスバーに「 file:/// 」と表示されている場合はサーバ上ではありません…Ajaxのセキュリティ制約でエラーになります)

## 3. 指定したファイルを表示させる

指定したファイルを表示させたい場合は、viewer.html?file=test.pdf のような形でビューアのHTMLにパラメータとしてファイル名を渡します。

![image](https://qiita-image-store.s3.amazonaws.com/0/782/4fd57dab-367b-4777-2262-a037ef21113d.png)

(GoogleのトップページをPDFにして表示してみたところ)

ファイル名だけの指定でPDFファイルを表示させたい場合はviewer.htmlと同じ位置に配置してください。PDFファイルが別フォルダにある場合はviewer.htmlからの相対パスか、絶対URL、絶対パスのいずれかで指定できます。

例えばviewer.htmlのあるフォルダの上のフォルダにtest.pdfを配置した場合は下記のような指定になります。

|種類  |指定の仕方  |
|---|---|
|相対パス  |?file=../test.pdf  |
|絶対パス  |?file=/pdfjs-1.4.20-dist/test.pdf  |
|絶対URL  |?file=http://localhost/pdfjs-1.4.20-dist/test.pdf  |

※URLは自サーバ内(厳密にはhttp/https、ドメイン、ポートが同じ)のURLである必要があります。

基本的にはこれで最低限使えると思います。

技術的な補足: CORS(Cross Origin Resource Sharing。Ajaxで別サーバのファイル読み込みを許可する)の設定をすれば別サーバのURLでも読めるような気がしますが、app.jsのvalidateFileURL()のコメントを見るとソースを少し弄らないといけないみたいです。(「Removing of the following line will not guarantee that the viewer will start accepting URLs from foreign origin -- CORS headers on the remote server must be properly configured.」「次の行を削除してもビューアが外部オリジンのURLを受け付け始めることを保証するものではありません…リモートサーバのCORSヘッダが適切に設定されていなければなりません」)

## &lt;iframe&gt;で埋め込む

3で表示を確認してOKだったらそのURLをコピーして、埋め込みたいHTML内で&lt;iframe&gt;のsrcにURLを設定すれば大丈夫です。

```html
<iframe width="400" height="300" src="http://localhost/pdfjs-1.4.20-dist/web/viewer.html?file=test.pdf">
```

widthやheightなどは自由に設定してください。CSSで設定してもよいです。

![image](https://qiita-image-store.s3.amazonaws.com/0/782/fa974985-c7cb-82e2-bc71-6fb37f13b256.png)

(Bootstrap v3と組み合わせてみた例)

## 今までにあった質問と回答

### Q. インターネット回線の環境が悪いPCだと読み込みがとても遅いです。

PDF自体のファイルサイズ以外ではbuild/pdf.worker.js が1.3MBありその部分で読み込みが引っかかるようです。ファイルをminify(圧縮)したりキャッシュすると少しだけ軽減できますが、根本的な解決は…わかったら教えてください。

### Q. PDF内に設定したリンクが動作しません。http://kichipoyo.hatenablog.com/entry/2013/11/21/223527 を見ると自力で作るしかないように思いました。

リンクのアドレスが絶対URL(http:// や https:// などからはじまらないURL)ではない場合は動作しません。絶対URLであれば何もしなくても動作します。

(リンク先の記事は2013年の記事ですしviewer.htmlではなく別口で試されているものです。リンクが絶対URLでない場合はAdobe ReaderでPDFを開いても動かないはずです)

### Q. PDFのリンクを新しいタブで開きたいです。

viewer.jsの457行目あたりにある「`externalLinkTarget: 0,`」を「`  externalLinkTarget: 2,`」にすると新しいタブで開くようになります。0や1の意味はpdf.js内に記載してあるLinkTargetという部分を見るとわかりますが、下記のとおりです。

|値|名前|意味|
|---|---|---|
|0|NONE|通常リンク|
|1|SELF|PDF.jsの表示している場所と同じ場所で開く|
|2|BLANK|新しいウィンドウで開く(タブブラウザの場合はタブ)|
|3|PARENT|親のウィンドウで開く|
|4|TOP|最上位のウィンドウで開く|

(&lt;a&gt;のtarget属性と同じです)

ソースを直接変更せずに行う場合は、viewer.html内のviewer.jsを読み込んだ直後などで「`<script>PDFViewerApplication.preferences.set("externalLinkTarget", 2);</script>`」などと記載するとよいです。(外部ファイルからスクリプトを読み込んでもよいです)

### Q. ファイルを開くボタンとしおりマークのボタン(「現在のビュー」)は不要だと思います。非表示にしたいです。

ビューアは基本的にHTMLなので、ボタンのidやclassをChromeのデベロッパーツールなどで確認してCSSでdisplay: noneすれば消えます。ファイルを開くボタンとしおりマークのボタンはviewer.cssに下記を追加するなどで消せます。

```css
#openFile, 
#viewBookmark, 
#secondaryOpenFile, 
#secondaryViewBookmark { 
    display: none !important;
}
```

(secondary～は、画面サイズが小さい場合のボタン(メニュー項目)です)

### Q. &lt;iframe&gt;でPDF.jsを埋め込むとフルスクリーン用のボタンが消えてしまいます。

&lt;iframe&gt;にallowfullscreen属性を追加すると、&lt;iframe&gt;内でもフルスクリーン用のボタンが使えるようになります。

```html
<iframe width="400" height="300" src="http://localhost/pdfjs-1.4.20-dist/web/viewer.html?file=test.pdf" allowfullscreen>
```

(技術的な補足: フルスクリーン用のボタン(button#presentationMode)はviewer.js内のPDFViewerApplication.supportsFullscreenの値がtrueかfalseかで表示が切り替わります)

### Q. &lt;iframe&gt;時でフルスクリーンボタンを押したときは別タブで開くようにしたいです。

フルスクリーンモードは拡大縮小ができない(ホイールスクロールがページめくりになっていてズームメニューも消える)など不便な部分があります。手っ取り早く対処するには、viewer.jsのPDFPresentationMode.prototypeにあるrequestを下記のようにします。(「追加」とある部分から下4行を追加。&lt;iframe&gt;上でない場合は通常通り)

```js
  PDFPresentationMode.prototype = {
    /**
     * Request the browser to enter fullscreen mode.
     * @returns {boolean} Indicating if the request was successful.
     */
    request: function PDFPresentationMode_request() {
      if (this.switchInProgress || this.active ||
          !this.viewer.hasChildNodes()) {
        return false;
      }
      // 追加: <iframe>上で表示されている場合(トップウィンドウが違う場合)は新規タブを開いて終わります。
      if (window.top != window) {
        window.open(location.href);
        return true;
      }

      this._addFullscreenChangeListeners();
      this._setSwitchInProgress();
      this._notifyStateChange();

      if (this.container.requestFullscreen) {
        this.container.requestFullscreen();
      } else if (this.container.mozRequestFullScreen) {
        this.container.mozRequestFullScreen();
      } else if (this.container.webkitRequestFullscreen) {
        this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
      } else if (this.container.msRequestFullscreen) {
        this.container.msRequestFullscreen();
      } else {
        return false;
      }

      this.args = {
        page: this.pdfViewer.currentPageNumber,
        previousScale: this.pdfViewer.currentScaleValue,
      };

      return true;
    },
```

※ 本体を書き換えないもう少しまともな方法がわかれば教えてください。