はじめに
pdfのサムネールを自動でって話があって・・
perlとかならImageMagickとかあるけど・・
JavaScriptでできないかしらべてみた。
pdfThumbnails
下記が見つかった。。
https://github.com/scandel/pdfThumbnails
内部的には
PDF.jsが必要ぽい。
https://mozilla.github.io/pdf.js/
注意なのが現在 2024年でバージョン4系が公開されているが、pdfThumbnailsではバージョン3系で動作した。
バージョン4だとmjs系なので、pdfjsLibあたりが定義がいるとか。そんなとこ・・pdfThumbnailsではバージョン2以上と記載もあるが
バージョン3の最新で筆者は行った。。
下記を解凍して、ディレクトリ名をpdfjsにしてその中にbuildが入る感じで・・
pdfjs-3.11.174-dist.zip
デモソースは下記に変更・・
<script src="pdfThumbnails.js" data-pdfjs-src="pdfjs/build/pdf.js"></script>
PDF.jsバージョン4から拡張子がECMAScript Modules (mjs)になっているので、クライアントサイドでつかうと変更とかめんどうなので・・
アパッチに下記とか・・
AddType text/javascript mjs
面倒なので・・わかる人だけ・・バージョン4・・わからない場合は。。バージョン3を・・
nodeがわかるあにきたちは。。バージョン4で・・
関連
PDF.jsのviewer.htmlの応用
https://www.omakase.net/blog/2021/02/pdfjsviewerhtml.html
V3使いかた
<script src="/path/to/pdfThumbnails.js" data-pdfjs-src="pdfjs/build/pdf.js"></script>
手法的には、遅延読み込みLazy Loadとか競合しそうかな。
<img data-pdf-thumbnail-file="/my/file.pdf" src="pdf.png">
生成する画像サイズの指定は、下記で・・
<img data-pdf-thumbnail-file="/my/file.pdf" data-pdf-thumbnail-width="200">
<img data-pdf-thumbnail-file="/my/file.pdf" data-pdf-thumbnail-height="150">
data-pdf-thumbnail-fileにPDFファイル名とパス
srcは表示されない場合の画像
pdfThumbnails.js
ソースは、PDFを1ページ目だけキャンパスに表示させて、toDataURL(base64)でimg srcに入れる感じ・・
/**
* Find all img elements with data-pdf-thumbnail-file attribute,
* then load pdf file given in the attribute,
* then use pdf.js to draw the first page on a canvas,
* then convert it to base64,
* then set it as the img src.
*/
var createPDFThumbnails = function(){
var worker = null;
var loaded = false;
var renderQueue = [];
// select all img elements with data-pdf-thumbnail-file attribute
var nodesArray = Array.prototype.slice.call(document.querySelectorAll('img[data-pdf-thumbnail-file]'));
if (!nodesArray.length) {
// No PDF found, don't load PDF.js
return;
}
if (!loaded && typeof(pdfjsLib) === 'undefined') {
var src = document.querySelector('script[data-pdfjs-src]').getAttribute('data-pdfjs-src');
if (!src) {
throw Error('PDF.js URL not set in "data-pdfjs-src" attribute: cannot load PDF.js');
}
var script = document.createElement('script');
script.src = src;
document.head.appendChild(script).onload = renderThumbnails;
loaded = true;
} else {
renderThumbnails();
}
function renderThumbnails() {
if (!pdfjsLib) {
throw Error("pdf.js failed to load. Check data-pdfjs-src attribute.");
}
nodesArray.forEach(function(element) {
if (null === worker) {
worker = new pdfjsLib.PDFWorker();
}
var filePath = element.getAttribute('data-pdf-thumbnail-file');
var imgWidth = element.getAttribute('data-pdf-thumbnail-width');
var imgHeight = element.getAttribute('data-pdf-thumbnail-height');
pdfjsLib.getDocument({url: filePath, worker: worker}).promise.then(function (pdf) {
pdf.getPage(1).then(function (page) {
var canvas = document.createElement("canvas");
var viewport = page.getViewport({scale: 1.0});
var context = canvas.getContext('2d');
if (imgWidth) {
viewport = page.getViewport({scale: imgWidth / viewport.width});
} else if (imgHeight) {
viewport = page.getViewport({scale: imgHeight / viewport.height});
}
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render({
canvasContext: context,
viewport: viewport
}).promise.then(function () {
element.src = canvas.toDataURL();
});
}).catch(function() {
console.log("pdfThumbnails error: could not open page 1 of document " + filePath + ". Not a pdf ?");
});
}).catch(function() {
console.log("pdfThumbnails error: could not find or open document " + filePath + ". Not a pdf ?");
});
});
}
};
if(document.readyState === "complete" || (document.readyState !== "loading" && !document.documentElement.doScroll)) {
createPDFThumbnails();
} else {
document.addEventListener("DOMContentLoaded", createPDFThumbnails);
}
さいごに
実際動かしてみると・・PDFのサイズがでかいものをたくさんリストするような使い方だと、サムネール表示が遅いです。
その場合、ブラウザー側のメモリ、スペックも必要かな・・って感じ
画面設計によっては使い道はありそう。