web-dev-qa-db-fra.com

Impression d'un fichier PDF avec Electron JS

J'essaie de créer une application Electron JS qui a pour but d'imprimer des PDF de format lettre.

Voici mon extrait de code pour l'impression:

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});
});

Mes problèmes sont les suivants: si j'ai print({silent:true}) mon imprimante imprime une page vide. Si j'ai print({silent:false}), l'imprimante imprime de la même manière que la capture d'écran, avec en-têtes, commandes, etc.

enter image description here

J'ai besoin d'une impression silencieuse du contenu PDF, et je n'arrive pas à le faire pendant des jours. Quelqu'un a-t-il vécu la même chose avec Electron?

22
Grig Dodon

Si vous avez déjà le fichier pdf ou que vous enregistrez le pdf avant d'imprimer "je suppose que c'est", vous pouvez saisir l'emplacement du fichier, puis vous pouvez utiliser le processus externe pour faire l'impression en utilisant child_process.

Vous pouvez utiliser lp command ou PDFtoPrinter pour Windows

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.'
        );
}

J'espère que ça aide.

Modifier: Vous pouvez également utiliser SumatraPDF pour Windows https://github.com/sumatrapdfreader/sumatrapdf

6
zer09

La façon la plus simple de procéder consiste à afficher les pages PDF en éléments de canevas individuels sur une page à l'aide de PDF.js, puis d'appeler print.

J'ai corrigé ce Gist pour utiliser la version PDF.js (v1) pour laquelle il a été conçu et c'est probablement un bon point de départ.

C'est essentiellement ce que fait la visionneuse pdf électron/chrome, mais maintenant vous avez un contrôle total sur la mise en page!

<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

Puisque vous utilisez contents.print([options], [callback]) je suppose que vous souhaitez imprimer sur du papier et non sur votre disque.


La réponse à votre problème est simple. C'est l'événement que vous écoutez qui est à l'origine de l'erreur. Donc, si vous faites simplement ceci:

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

tout fonctionnera bien si l'imprimante par défaut est la bonne. J'ai testé cela et il fera plus ou moins son travail. Vous pouvez changer mon événement en n'importe quel événement que vous aimez, la partie importante est l'attente avec setTimeout. Le PDF que vous essayez d'imprimer n'est tout simplement pas disponible dans le cadre lorsque vous utilisez silent:true.

Cependant, permettez-moi d'entrer dans les détails ici un peu pour clarifier les choses:

Electron chargera des fichiers ou des URL dans une fenêtre créée (BrowserWindow) qui est liée aux événements. Le problème est que chaque événement "peut" se comporter différemment sur différents systèmes. Nous devons vivre avec cela et ne pouvons pas changer cela facilement. Mais le savoir contribuera à améliorer le développement d'applications personnalisées.

Si vous chargez des URL ou des fichiers HTML, tout fonctionnera sans définir d'options personnalisées. En utilisant des PDF comme source, nous devons utiliser ceci:

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.
  }
});

indice: sans webPreferences: { plugins: true } votre source PDF sera téléchargé au lieu d'être chargé dans la fenêtre.

Cela dit, vous allez charger votre PDF dans le webContents de votre fenêtre. Nous devons donc écouter les événements compatibles avec BrowserWindow. Vous avez tout fait correctement, le la seule partie que vous avez manqué est que l'impression est une autre interface.

L'impression capturera votre webContents telle qu'elle est lorsque vous appuyez sur "imprimer". C'est très important de savoir quand on travaille avec des imprimantes. Parce que si quelque chose se charge un peu plus longtemps sur un système différent, par exemple, la visionneuse de PDF sera toujours gris foncé sans les lettres, alors votre impression imprimera le fond gris foncé ou même les boutons.

Ce petit problème est facilement résolu avec setTimeout().

Questions et réponses utiles pour l'impression avec un électron:

Cependant, il y a beaucoup plus de problèmes possibles avec l'impression, car la plupart du code est à huis clos sans API mondiale à utiliser. Gardez à l'esprit que chaque imprimante peut se comporter différemment, ce qui vous aidera à tester sur plus de machines.

3
Megajin

Il semble donc que vous essayez de télécharger le fichier pdf plutôt que d'imprimer un pdf de l'écran actuel, ce que print essaie de faire. En tant que tel, vous avez deux options.

1) Désactiver la visionneuse pdf native dans électron:

Si vous ne vous souciez pas de la fenêtre électronique affichant le pdf, la désactivation de la visionneuse PDF native dans electron devrait plutôt le faire traiter le fichier comme un téléchargement et tenter de le télécharger.

new BrowserWindow({
  webPreferences: {
    plugins: false
  }
})

Vous pouvez également vouloir vérifier api DownloadItem de l'électron pour faire quelques manipulations sur l'endroit où le fichier sera enregistré.

2) Téléchargez le pdf via une autre API

Je ne vais pas donner de détails sur celui-ci car vous devriez être en mesure de trouver vous-même des informations à ce sujet, mais en gros, si vous voulez télécharger le fichier quelque part, vous pouvez utiliser une autre API de téléchargement comme un AJAX bibliothèque pour télécharger le fichier et l'enregistrer quelque part. Cela vous permettrait potentiellement de rendre le document dans une fenêtre électronique également, car une fois que vous lancez le téléchargement, vous pouvez probablement rediriger la fenêtre vers l'url pdf et avoir le visualiseur natif le gère.

Pour faire court, il me semble que vous ne voulez pas vraiment imprimer à partir d'électrons, vous voulez simplement enregistrer le fichier pdf que vous affichez. L'impression à partir d'électrons rendra ce que vous voyez à l'écran, pas le document pdf lui-même, donc je pense que vous avez mal compris l'objectif de l'impression. J'espère que cela vous aide, bonne chance!

=== EDIT ===

Malheureusement, je ne pense pas qu'il existe un moyen d'imprimer le fichier directement à partir d'électrons, car l'impression d'électrons sert à imprimer le contenu de l'affichage des électrons. Mais vous devriez pouvoir télécharger le fichier via une simple demande de fichier (voir ci-dessus).

Ma recommandation pour vous serait de créer une page pour prévisualiser le fichier. Ce serait une page indépendante, pas la visionneuse pdf intégrée. Vous pouvez ensuite insérer un bouton quelque part sur la page pour télécharger le pdf par certains moyens et ignorer les invites d'emplacement d'enregistrement (cela devrait être assez facile de trouver de la documentation).

Ensuite, afin d'avoir votre aperçu, sur la même page, vous pouvez avoir un webview tag dans votre page, qui affichera le visualiseur pdf natif. Pour que la visionneuse PDF native fonctionne dans la balise webview, vous devez inclure l'attribut plugins dans la balise. C'est une balise booléenne, donc sa simple présence suffit, comme <webview ... plugins> Cela active la prise en charge des plug-ins pour le rendu de cette vue Web qui est requis pour la visionneuse PDF.

Vous pouvez modifier le style de taille de cette balise sur la page selon vos besoins. Une astuce pour se débarrasser des options de téléchargement et d'impression afin qu'un utilisateur ne puisse pas les appuyer consiste à ajouter #toolbar=0 à la fin de l'URL pdf pour empêcher la visionneuse pdf native d'afficher la barre d'outils supérieure avec ces boutons.

Ainsi, de cette façon, vous pouvez avoir votre aperçu, vous assurer que l'utilisateur ne peut pas utiliser le téléchargement ou l'impression intégré à partir de la visionneuse PDF avec l'interface utilisateur supplémentaire, et vous pouvez ajouter un autre bouton pour le télécharger afin qu'il puisse être imprimé plus tard.

2
obermillerk