LoginSignup
19
13

More than 5 years have passed since last update.

TypeScriptでpdfjsを使ってPDFの先頭ページを表示しようと試行錯誤した話

Last updated at Posted at 2018-09-07

TL;DR

  • npmでpdfjs-distをインストールして使ったら失敗した。
  • 公式サイトからstable版をダウンロードして来たら成功した。

pdfjs

pdfjsの説明は、本家gitのページをgoogle先生の翻訳を参照します。

PDF.jsはHTML5で構築されたPortable Document Format(PDF)ビューアです。

PDF.jsはコミュニティ主導型であり、Mozilla Labsによってサポートされています。私たちの目標は、PDFを解析してレンダリングするための汎用のWeb標準ベースのプラットフォームを作成することです。

PDFを表示しようとした場合、PDFを読み込んでghostscriptで画像に変換して画像を表示してもいいのですが、勉強も兼ねてPDF.jsを使用して表示できないか試しました。

npmでpdfjs-distをインストール

「npm pdfjs」で検索すると、2018/5/29時点では先頭にpdfjs-distがきて、次にpdfjsが来ています。
それぞれのページを開いてrepositoryを確認すると、pdfjs-distがmozilla公式のようです。
実際、pdf.jsのgitのページの中にも、NPMとBowerにはpdfjs-distという名前で登録されている旨の記載があります。

というわけでpdfjs-distと、TypeScriptで使いたいので@types/pdfjs-distを合わせてインストール。

$ npm install --save pdfjs-dist @types/pdfjs-dist

今回インストールされたのは、

バージョンに開きがあるのが非常に気になりますが、@types/pdfjs-distのnpmのサイトを確認したところ、何年も更新が止まっているわけではないみたいなので、とりあえず使ってみます。

pdfjs-distを使う

試行錯誤1

なにも考えずに使ってみます。

import { PDFJS } from "pdfjs-dist";

PDFJS.getDocument( "hoge.pdf" )
    .then( ( pdfDoc: PDFDocumentProxy ) => {
        ...
    } );

結果は以下の通り。

Uncaught TypeError: Cannot read property 'getDocument' of undefined

なんでやねーん、というわけでこの書き方では失敗しました。
それにしても関連記事、少ないです...皆さんあまりpdfjs-distとTypeScriptの組み合わせは使わないのかな。

試行錯誤2

修正版はこちら。

import { PDFDocumentProxy, PDFJSStatic } from "pdfjs-dist";

const PDFJS: PDFJSStatic = require( "pdfjs-dist" );

PDFJS.getDocument( "hoge.pdf" )
    .then( ( pdfDoc: PDFDocumentProxy ) => {
        ...
    } );

これは動きました。
よしよし。

しかし、実際にhtmlから呼び出してみると、コンソールにはWarningが表示されてしまいました。

Warning: Error during font loading: The CMap "baseUrl" parameter must be specified, ensure that the "cMapUrl" and "cMapPacked" API parameters are provided.

表示されたPDFと、Acrobatで表示したPDFを見比べると、文字が表示されていません。
とりあえず、cMapUrlとcMapPackedを確認するように言われているので確認します。

cMapUrlはcmapsのディレクトリまでのパスを指定します。
cmapsは、node_modules/pdfjs-dist/cmapsを指定しました。

cMapPackedは、cmapの拡張子がbcmapだったらtrueのようです。

import { PDFDocumentProxy, PDFJSStatic } from "pdfjs-dist";

const PDFJS: PDFJSStatic = require( "pdfjs-dist" );
PDFJS.cMapUrl = "パスを入力";
PDFJS.cMapPacked = true;

PDFJS.getDocument( "hoge.pdf" )
    .then( ( pdfDoc: PDFDocumentProxy ) => {
        ...
    } );

結果やいかに。

Warning: Error during font loading: The CMap "baseUrl" parameter must be specified, ensure that the "cMapUrl" and "cMapPacked" API parameters are provided.

えぇぇ...。

Chromeの開発者ツールで中身をのぞいてみますが、原因特定できず。
途中まではcMapUrlに値が入っているのに、いざcMapUrlを使っている部分ではundefinedになっているという。
誰かわかる人、教えてください...。

試行錯誤3

npmを使ったインストールにこだわるのはやめました。
公式サイトからstable版をダウンロードして来て、pdf.jsをhtmlで指定することにします。

DLしたzipファイルを解凍して、必要ファイル(cmaps/、pdf.js、pdf.worker.js)をコピーして以下のような構成にします。

cmaps/
index.html
index.js
pdf.js
pdf.worker.js

htmlにscriptタグを追加。

...
<script src="./pdf.js"></script>
...

ts側で読み込み。

const PDFJS: PDFJSStatic = (window as any).PDFJS;

PDFJS.cMapUrl = "cmaps/";
PDFJS.cMapPacked = true;

はい、動きました。

うーん。
pdfjs-distがなぜ動かなかったのかわからない。

PDFを表示するTypeScriptのコード

今回の用途としてはサムネイル表示したかっただけなので、コードとしては先頭ページの表示のみです。
ページ遷移とかは考慮していません。

const PDFJS: PDFJSStatic = (window as any).PDFJS;

PDFJS.cMapUrl = "cmaps/";
PDFJS.cMapPacked = true;

async renderThumbnail(
    canvas: HTMLCanvasElement,
    size: SizeType,
    buff: ArrayBuffer
): Promise<any> {
    const pdfDoc = await PDFJS.getDocument( new Uint8Array( buff ) );
    const page = await pdfDoc.getPage( 1 );
    let viewport = page.getViewport( 1, 0 );
    const larger = viewport.height > viewport.width ? viewport.height : viewport.width;
    const scale = size / larger;
    const rotate = 0;

    viewport = page.getViewport( scale, rotate );
    const ctx = canvas.getContext( "2d" )!;

    const renderContext: PDFRenderParams = {
        canvasContext: ctx,
        viewport: viewport
    };
    canvas.height = viewport.height;
    canvas.width = viewport.width;
    this.setStyle( {
        width: viewport.width + "px",
        height: viewport.height + "px"
    } );

    page.render( renderContext );
}
19
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
13