pdf.js-controllerというライブラリを書きました。

名前の通りmozilla/pdf.jsを扱うものです。 PDFをスライドのようなページめくりをするものを作るときに簡単に作れるようにする目的で作成しています。

実際に以下のスライドはこのライブラリを使って動作しています。

http://azu.github.io/slide/2015/year-end/pdf.js.html

使い方

npm install pdf.js-controller

インストールして、以下のように書くだけでとりあえずpdfを表示できます。 普通にpdf.jsを扱うと文字列の選択ができない、日本語が文字化けする、リンクがクリック出来ないなどハマりどころがたくさんあります。

このライブラリではpdfjs-distのディレクトリをpdfDistDirで指定する以外はあまり意識しなくても自動的にやってくれます。 (pdfjs-distはdependenciesとして入ってるので自動的に入ります)

// container element
var container = document.getElementById("pdf-container");

var PDFController = require("pdf.js-controller");
var controller = new PDFController({
    container: container,
    // path to dir of pdfjs-dist
    pdfDistDir: __dirname + "/node_modules/pdfjs-dist/"
});
// path to URL of pdf.
// Apply CORS to this path. It means that the URL should be same origin.
var PDFURL = "./example.pdf";
controller.loadDocument(PDFURL)
    .then(initializedEvent)
    .catch(function (error) {
    console.error(error);
});

container.addEventListener(PDFController.Events.before_pdf_rendering, function (event) {
    // before render
});
container.addEventListener(PDFController.Events.after_pdf_rendering, function (event) {
     // after render
});

function initializedEvent() {
    window.addEventListener("resize", function (event) {
        controller.fitItSize();
    });
    document.onkeydown = function (event) {
        var kc = event.keyCode;
        if (event.shiftKey || event.ctrlKey || event.metaKey) {
            return;
        }
        if (kc === 37 || kc === 40 || kc === 75 || kc === 65) {
            // left, down, K, A
            event.preventDefault();
            controller.prevPage();
        } else if (kc === 38 || kc === 39 || kc === 74 || kc === 83) {
            // up, right, J, S
            event.preventDefault();
            controller.nextPage();
        }

    };
}

pdfjs-distには言語別の情報が入ったcmapsというデータやWebWorkerのスクリプトが含まれています。 そのため、ウェブに上げるときはpdfDistDirのディレクトリも参照出来る場所に必要です。

仕組み

以下の画像をみてもらうと分かりますが、pdf.jsはCanvasとテキスト、アノテーションの3つのレイヤーを使って描画しています。

Canvasにはそもそも文字列選択機能が存在しないため、このような作りになっています。 つまりCanvasの描画の上に透明なdivにテキストを流しこんだり、クリック出来るようにリンクを置いたりしています。

Firefoxの3D Viewで見てみるとそれぞれがレイヤーになっていることが分かりやすいです。

全体像3D

3D View

CanvasはPDFの内容を描画しています。

Canvas Layer

テキストレイヤーにはテキストが流し込まれています。

Text Layer

アノテーションコンテナにはリンクなどのPDFにおけるアノテーション情報が入っています。

Annotation Layer

デフォルトではCanvasのレイヤーしかないため、テキストやアノテーションは自分で行う必要があります。 そこを作るのが複雑なので、今回はその辺を隠蔽したpdf.js-controllerを作りました。

元々、azu/slide-pdf.jsで実装してありましたが、ライブラリとして切り離した感じです。

FirefoxのビルトインのpdfビューアライクのUIを利用したいだけの場合は、pdf.js/viewer.html at master · mozilla/pdf.jsあたりを見るといいです。(iframeで表示するとかできます)

おわりに

スライド共有サービス sharedoc を作りました - onk.ninjaを見ていて、未だにpdf.jsの扱いがとっても面倒そうだったのでライブラリとして切り出しました。

pdf.jsは意外と動いて面白いのと、技術的スライドサービスでリンクがクリック出来ないのは辛いので何か頑張って欲しいと思いました。