フロントのみでPDFファイルのサムネイルを用意する
とある案件でアップロードされたPDFファイルの1ページ目をサムネイル表示したいという要件のタスクがきました。
バックエンドはPHP、フロントはJavaScriptとHTMLでレンタルサーバーで運用というシンプルな環境だったため特に問題はないと思いました。
PHPでPDFを扱う場合はImageMagickがあれば簡単にできます。
ImageMagickにはPDFをJPGなどの画像ファイルに変換する機能があるため、ImageMagickをインストールすればあとはコマンドラインからPDF変換コマンド実行したり、Imagickを用意してPHP処理内でPDFの変換を行えます。
ImageMagickやImagickの詳細については今回の本題から逸れるため割愛します。
問題点
最初の想定では前述のImageMagickとImagickを前提に考えていましたが1つ問題がありました。
今回の環境はレンタルサーバーに予めインストール済みのApacheとPHPを利用しますが、こちらからはFTP通信以外が出来ずサーバーに手を加えることが出来ませんでした。(格安サーバーではよくあることらしいのですが知りませんでした…)
代案
サーバーにツールをインストールすることが一切出来ず、提供されたものにはImageMagickが含まれていなかったため他の方法を探しました。
基本的にPDFや画像を扱う場合はバックエンドでやるものだと考えましたが、探してみるとフロント側でも出来ることが分かりました。
今回はPDF.jsというライブラリを採用しました。
PDF.jsはMozillaが開発したPDFビューアでPDFファイルをJavaScriptのみで画像にレンダリングすることが出来ます。
これを使いフロント側でPDFを画像にしてそのままサーバーにアップロードさせることで今回の要件を満たすことが出来ました。
簡易的な使い方
最低限のHTMLとJSの記述になります。
<!-- PDFをレンダリングするスペース -->
<canvas id="pdf-canvas" style=""></canvas>
<!-- PDF.jsを配置したpath -->
<script src="pdfjs/pdf.js"></script>
<script>
function convertPdfToJpg (pdf_path) {
// PDF.jsを配置したpath
pdfjsLib.workerSrc = '/js/pdfjs/pdf.worker.js';
// サムネイルを作りたいPDFのpath
var pdfData = 'test.pdf';
// PDFをレンダリングするスペース
var canvas = document.getElementById('pdf-canvas');
pdfjsLib.getDocument(pdfData).then(function (pdf) {
// 1ページ目を取得する
return pdf.getPage(1);
}).then(function (page) {
// Canvas に1ページ目の内容を描画
var scale = 0.5;
var viewport = page.getViewport(scale);
var context = canvas.getContext('2d');
// canvas.style.display = "none"; // 非表示にする場合
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: context,
viewport: viewport
};
return page.render(renderContext);
}).then(() => {
return new Promise(resolve => {
canvas.toBlob(blob => {
var reader = new FileReader();
reader.readAsDataURL(blob);
var base64data = '';
reader.onloadend = function() {
// 作成されたtemporary画像
base64data = reader.result;
}
resolve(blob);
}, "image/jpeg");
});
}).then(blob => {
}).catch(error => {
console.log("error");
});
}
</script>
今回は特殊な環境下だったためこの方法で解決しましたが、こういった処理は可能な限りサーバーサイドで処理するべきだと思います。
コメントを残す