大量の PDF を表示する必要がある nw.js アプリケーションを作成中です。アプリケーションを初めて起動すると、PDF が最初にダウンロードされます。初期化フェーズでは、リストに表示される各 PDF のサムネイルも作成する必要があります。
PDF がいくつかある場合、サムネイルの生成自体は問題にならないようです。canvas 要素を作成し、PDF.js に最初のページを描画させてから、キャンバスを PNG に保存することで機能します。
問題は、実行間で PDF.js が PDF をアンロードしていないように見えることです。通常、1MB の PDF ファイルを 20 個読み込むと、nw.js は約 500MB の RAM を使用します。現在、100 以上、場合によっては数千の PDF があるため、各サムネイル間で RAM を解放する方法を理解する必要があります。約 80 個の PDF で、nw.js は既に 2 GB の RAM を使用しており、ラップトップをフリーズさせているためです。メモリが不足しています。
この問題を示す簡単なテストを作成しました。
var fs = require("fs");
var Q = require("q");
var glob = require("glob");
var canvas = document.createElement("canvas");
var ctx = canvas.getContext('2d');
PDFJS.workerSrc = "pdf.worker.js";
function pdf(pdfFile) {
return new Q.Promise(function (fulfill, reject) {
PDFJS.getDocument(pdfFile).then(function (pdf) {
pdf.getPage(1).then(function (page) {
var viewport = page.getViewport(0.5);
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
page.render(renderContext).then(function () {
//set to draw behind current content
ctx.globalCompositeOperation = "destination-over";
//set background color
ctx.fillStyle = "#ffffff";
//draw background / rect on entire canvas
ctx.fillRect(0, 0, canvas.width, canvas.height);
var img = canvas.toDataURL("image/png");
img = img.replace(/^data:image\/png;base64,/, "");
fs.writeFile(pdfFile + ".png", img, 'base64', function (err) {
console.log("Done thumbnail for: " + pdfFile);
fulfill();
});
});
});
});
});
}
glob("pdf/*.pdf", function (err, files) {
if (err) {
console.log(err);
} else {
function generate(file) {
console.log("Generating thumb for: " + file);
pdf(file).then(function() {
if(files.length > 0) next();
});
}
function next() {
var file = files.pop();
generate(file);
}
next();
}
});
私は前にこのようなことをしたことがありません。すべての親指に同じキャンバスを再利用しようとしましたが、何も変わらないようです。
開発者ツールでヒープ スナップショットを実行して、RAM をすべて占有しているものを確認しようとしましたが、どう思いますか? スナップショットを実行する前にガベージ コレクションをトリガーするように見えるため、nw.js はスナップショットを実行する前に 500MB から約 100MB になります。これにより、オブジェクトは実際には削除対象としてマークされているが、コンピューターの RAM が不足する前に GC を実行する機会は決してないと信じてしまいます。ただし、20 個のファイルをロードしてから待機しても、GC はトリガーされず、RAM が不足することもありません。
PDF.js の API とドキュメントを確認しようとしましたが、次の PDF をロードする前に PDF をアンロードする方法について言及しているものは見つかりませんでした。
どのように進めるべきかについてのアイデアはありますか?私が持っていたアイデアは、いくつかの外部ツールを呼び出すか、node-ffi を使用して呼び出す ac/c++ lib を作成することでしたが、PDF.js を使用して後の状態で PDF を表示する必要がありました。同じ問題が再び発生するだけです。