3

大量の 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 を表示する必要がありました。同じ問題が再び発生するだけです。

4

0 に答える 0