nwjs / nw.js

Call all Node.js modules directly from DOM/WebWorker and enable a new way of writing applications with all Web technologies.
https://nwjs.io
MIT License
40.32k stars 3.89k forks source link

Custom printing API #4911

Closed rogerwang closed 5 years ago

rogerwang commented 8 years ago

As proposed in https://github.com/nwjs/nw.js/issues/1263#issuecomment-218741764

acicali commented 7 years ago

@karlkrach - since printing is synchronous, it will lock the main UI thread. Moving your print routine to a web worker may resolve your issue.

kailniris commented 7 years ago

@karlkrach Open a new window in a new render process (new_instance). You can safely print from there it wont freeze other windows in different threads.

maschinenzeitmaschine commented 7 years ago

hi! this was quick, thank you so much for helping me!!! new_instance does indeed solve the lag and i'm almost there but i'm afraid i do not fully understand the concept... what i did get to work:

from my main script i just open up the new window with nw.Window.open(toprinter, {show: true, new_instance: true});

the "toprinter"-string is a complete html-site including: <script>window.print( { printer: "EPSON_TM_T20II", headerFooterEnabled: false }); window.close();</script></body></html>

now, that does work and fixes the lag but:

or do i get the whole concept wrong? again, thank you so much for your help! karl

rdtsc commented 7 years ago

@karlkrach: it's been a while, but it might be that the Node context is not made available to the standalone data URI instance because of the lack of the node-remote pattern in the manifest. Regardless, I can't seem to get it to work either way with nw.Window.open.

Since #4418 is still open, you may want to try spawning an HTML file with new_instance:true and using it as a print container for a workaround. Alternatively, just save your print job files to a temp directory along with a bit of JS to invoke NW's print API. Below is a very crude example which should demonstrate the basic idea.

capture

package.json

{
  "name": "nwjs-print-test",
  "main": "index.html"
}

index.html

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>NW.js Print Test</title>
    <script>
      function getRandomString() {
        return Math.random().toString(32).slice(2);
      }

      function printAsync(html, printOpts, callback) {
        this.id = ++this.id || 1;

        const channel =
          new BroadcastChannel(`${nw.App.manifest.name}-print-job-${this.id}`);

        channel.onmessage = (event) => {
          switch(event.data) {
            case 'ready': {
              channel.postMessage(html);
            } break;

            case 'done': {
              channel.close();
              callback();
            } break;
          }
        };

        printOpts = encodeURIComponent(JSON.stringify(printOpts));

        nw.Window.open(`print.html?id=${this.id}&opt=${printOpts}`, {
          show: true,
          new_instance: true
        });
      }

      document.addEventListener('DOMContentLoaded', () => {
        const printBtn = document.querySelector('#print');

        printBtn.onclick = () => {
          printBtn.disabled  = true;
          printBtn.innerText = 'Printing in progress...';

          printAsync(getRandomString().repeat(10000), {
            pdf_path: `./tmp/${getRandomString()}.pdf`,
            headerFooterEnabled: false
          }, () => {
            printBtn.disabled  = false;
            printBtn.innerText = 'Print';
          });
        };

        const counter = document.querySelector('#counter');
        setInterval(() => counter.innerText = (+counter.innerText + 1), 50);
      });
    </script>
  </head>
  <body>
    <p>App UI is responsive: <span id="counter">0</span></p>
    <button id="print">Print</button>
  </body>
</html>

print.html

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Printing...</title>
    <script>
      document.addEventListener('DOMContentLoaded', () => {
        const url = require('url'),
              qs  = require('querystring'),
              win = nw.Window.get();

        const {id, opt} = qs.parse(url.parse(window.location.href).query);

        const channel =
          new BroadcastChannel(`${nw.App.manifest.name}-print-job-${id}`);

        channel.onmessage = (event) => {
          document.body.innerHTML = event.data;

          setTimeout(() => {
            win.print(JSON.parse(opt));
            setTimeout(() => {
              channel.postMessage('done');
              channel.close();
              win.close();
            }, 1000);
          }, 1000);
        };

        channel.postMessage('ready');
      });
    </script>
  </head>
  <body style="word-wrap: break-word">
  </body>
</html>
maschinenzeitmaschine commented 7 years ago

hi rdtsc, ... wow! to be honest, it will take me some time to understand what you are doing there - i was hoping for this new_instance approach since i almost got that to work already and it did not seem that complicated but ok... if this is a known bug i guess there won't be much i can do about it. so, for the time being, thank you so much for helping me! i'll get back once i understand your code! all the best karl

maschinenzeitmaschine commented 7 years ago

again, hi rdtsc. i still do not fully understand your magic there but let me just say again: THANK YOU!!! this works perfectly well. silent, lag-free printing, yay! and actually you really saved my whole program with this since in the meantime i found out, that this printing lag would not only freeze my screen but also mess with some data coming from an arduino - which would have been a serious dealbreaker for my project. so, again! THANK YOU SO MUCH!!! all the best! karl

ps.: if i can get you a crate of beer for this, let me know!!!

Christywl commented 7 years ago

So this issue is resolved now?

elouf commented 6 years ago

Hi,

I'm trying to print a jpg file and i get some troubles... The preview is well generated but the printed page (as the pdf preview) stay blank...

capture d ecran 2017-11-15 a 10 31 20

capture d ecran 2017-11-15 a 10 35 31

                        let filename = 47_abeille.jpg;
                        let filePath = global.__dirname + '/_content/ressources/reperes/' + filename;
                        nw.Window.open('file://' + filePath, {
                            show: true,
                            new_instance: false,
                            width: 800,
                            height: 600
                        }, function (win) {
                            win.on('loaded', function () {
                                try {
                                    win.print({
                                        autoprint: false,
                                        landscape: true,
                                        headerFooterEnabled: true,
                                        headerString: filename,
                                        footerString: ''
                                    });
                                    win.close();
                                } catch (exception) {
                                    console.log('print exception', exception);
                                }
                            });
                        });

Have you any advice about this issue? Thanks

Christywl commented 6 years ago

It works fine for me on Mac with nwjs-sdk-v0.26.6.

<html>
<script>
 let filename = 'myw3schoolsimage.jpg';
                        let filePath = global.__dirname + '/' + filename;
                        nw.Window.open('file://' + filePath, {
                            show: true,
                            new_instance: false,
                            width: 800,
                            height: 600
                        }, function (win) {
                            win.on('loaded', function () {
                                try {
                                    win.print({
                                        autoprint: false,
                                        landscape: true,
                                        headerFooterEnabled: true,
                                        headerString: filename,
                                        footerString: ''
                                    });
                                    win.close();
                                } catch (exception) {
                                    console.log('print exception', exception);
                                }
                            });
                        });
</script>
</html>
screen shot 2017-11-16 at 10 44 23 am
elouf commented 6 years ago

I just tried with nwjs-sdk-v0.26.6 and get the same issue... It's so frustrating! I really don't understand what is happening...

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.