web-dev-qa-db-ja.com

Electron JSでPDFファイルを印刷する

レターサイズのPDFを印刷することを目的としたElectron JSアプリを作成しようとしています。

これは印刷用のコードのスニペットです:

_win = new BrowserWindow({
  width: 378, 
  height: 566, 
  show: true, 
  webPreferences: {
    webSecurity: false,
    plugins: true
  }
});

// load PDF
win.loadURL('file://' + __dirname + '/header1_X_BTR.pdf');

// if pdf is loaded start printing
win.webContents.on('did-finish-load', () => {
  win.webContents.print({silent: true, printBackground:true});
});
_

私の問題は:print({silent:true})を使用している場合、プリンターが空のページを印刷します。 print({silent:false})を使用している場合、スクリーンショットと同じように、ヘッダー、コントロールなどが印刷されます。

enter image description here

PDFコンテンツのサイレントプリントが必要です。何日もそれを行うことができません。Electronで同じことを経験した人はいますか?

22
Grig Dodon

PDFファイルが既にある場合、または「私はそうだと思います」を印刷する前にPDFを保存する場合は、ファイルの場所を取得し、外部プロセスを使用してchild_processを使用した印刷を実行できます。

Windowsの場合、lp commandまたは PDFtoPrinter を使用できます

const ch = require('os');

switch (process.platform) {
    case 'darwin':
    case 'linux':
        ch.exec(
            'lp ' + pdf.filename, (e) => {
                if (e) {
                    throw e;
                }
            });
        break;
    case 'win32':
        ch.exec(
            'ptp ' + pdf.filename, {
                windowsHide: true
            }, (e) => {
                if (e) {
                    throw e;
                }
            });
        break;
    default:
        throw new Error(
            'Platform not supported.'
        );
}

お役に立てば幸いです。

編集:WindowsでSumatraPDFを使用することもできます https://github.com/sumatrapdfreader/sumatrapdf

6
zer09

これを行う最も簡単な方法は、PDFページをPDF.jsを使用してページ上の個々のキャンバス要素にレンダリングしてから、printを呼び出すことです。

私は this Gist を修正して、それが設計されたPDF.jsバージョン(v1)を使用するようにしました。

これは基本的に、electron/chrome pdfビューアが行っていることですが、これでレイアウトを完全に制御できます!

<html>
<body>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/1.10.90/pdf.js"></script>
<script type="text/javascript">
function renderPDF(url, canvasContainer, options) {
    var options = options || { scale: 1 };
        
    function renderPage(page) {
        var viewport = page.getViewport(options.scale);
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        var renderContext = {
          canvasContext: ctx,
          viewport: viewport
        };
        
        canvas.height = viewport.height;
        canvas.width = viewport.width;
        canvasContainer.appendChild(canvas);
        
        page.render(renderContext);
    }
    
    function renderPages(pdfDoc) {
        for(var num = 1; num <= pdfDoc.numPages; num++)
            pdfDoc.getPage(num).then(renderPage);
    }
    PDFJS.disableWorker = true;
    PDFJS.getDocument(url).then(renderPages);
}   
</script> 

<div id="holder"></div>

<script type="text/javascript">
renderPDF('//cdn.mozilla.net/pdfjs/helloworld.pdf', document.getElementById('holder'));
</script>  

</body>
</html>
6
Tim

あなたはcontents.print([options], [callback])を使用しているので、ディスクではなく紙に印刷したいと思います。


あなたの問題への答えは簡単です。エラーの原因となっているのは、リスニングしているイベントです。したがって、単純にこれを行う場合:

_  winObject.webContents.on('did-frame-finish-load', () => {
    setTimeout(() => {winObject.webContents.print({silent: true, printBackground:true})}, 3000);
  });
_

デフォルトのプリンタが正しい場合、すべてが正常に動作します。私はこれをテストしました、そしてそれは多かれ少なかれその仕事をします。私のイベントを好きなイベントに変更できます。重要な部分はsetTimeoutで待機することです。印刷しようとしているPDFは、_silent:true_を使用する場合、フレームで使用できません。

ただし、わかりやすくするために、ここで少し詳しく説明します。

Electronは、イベントにバインドされている作成済みウィンドウ(BrowserWindow)にファイルまたはURLをロードします。問題は、すべてのイベントが異なるシステムで異なる「動作」をすることができることです。私たちはそれと共存しなければならず、これを簡単に変更することはできません。しかし、これを知ることはカスタムアプリの開発を改善するのに役立ちます。

URLまたはHTMLをロードすると、カスタムオプションを設定しなくてもすべてが機能します。ソースとしてPDFを使用する場合、これを使用する必要があります。

_import electron, { BrowserWindow } from 'electron';
const win = new BrowserWindow({
  // @NOTE I did keep the standard options out of this.
  webPreferences: { // You need this options to load pdfs
    plugins: true // this will enable you to use pdfs as source and not just download it.
  }
});
_

ヒント:_webPreferences: { plugins: true }_なしソースPDFウィンドウにロードされる代わりにダウンロードされます。

つまり、PDF=をウィンドウのwebContentsにロードします。したがって、BrowserWindowと互換性のあるイベントをリッスンする必要があります。あなたが見逃した唯一の部分は、印刷が別のインターフェースであるということでした。

印刷すると、「印刷」を押したときのwebContentsがそのままキャプチャされます。これは、プリンタを操作するときに知っておくべき非常に重要です。たとえば、別のシステムで何かが少し長く読み込まれる場合、たとえばPDFビューアが文字なしの濃い灰色のままである場合、印刷では濃い灰色の背景またはボタンが印刷されます。

その小さな問題はsetTimeout()で簡単に修正できます。

電子での印刷に役立つQ&A:

ただし、ほとんどのコードは世界規模のAPIを使用せずに密かに公開されているため、印刷に関してはさらに多くの問題が発生する可能性があります。すべてのプリンターは異なる動作をする可能性があるため、より多くのマシンでテストすると役立つことに注意してください。

3
Megajin