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

Andrew-Gee commented 8 years ago

How about something 'simple', like a print function on the nw Window:

nw.Window.get().print({
   printerName: 'Laser100',
   preview: false,
   headers: false
});

Would also need a function to return a list of all available printers.

kailniris commented 8 years ago

We are working on a project where printing is pretty important and it would be awesome to use an API like this. Here is a list of feature requests:

Thanks You!

AndryBray commented 8 years ago

@rogerwang Just saw electron supports win.printToPDF(options, callback). Any chance to build something like that?

rogerwang commented 8 years ago

@AndryBray it will be included.

Thanks to all the suggestions.

rogerwang commented 8 years ago

NW v0.14.6 LTS released with custom printing API http://nwjs.io/blog/v0.14.6/

kailniris commented 8 years ago

This was fast! Thanks You very much!

I tested it and there is two things i can't get to work: Clould not get the printer and pdf_path options to work. Landscape and headerFooterEnabled works fine. var win = nw.Window.get(); win.print({'printer': 'SHARP AR-5620N', 'landscape': false, 'headerFooterEnabled': false }); win.print({'pdf_path': 'c:\asd.pdf', 'landscape': false, 'headerFooterEnabled': false })

win.getPrinters returned this printer in one of its array->objects: deviceName: "SHARP AR-5620N"

It prints without print dialog but to the printer I last set in the print dialog before not to the printer option value path.

Windows 10, v0.14.6, the printer is a network printer, can print to it in chrome print dialog

rogerwang commented 8 years ago

@kailniris I made a fix and verify it working: http://dl.nwjs.io/live-build/06-02-2016/nw14-d775bb5-1a287bf-2a9e6e1-5a26102/v0.14.7/

Would you try it again and see if there are other issues? Thanks.

kailniris commented 8 years ago

Hello, I tried out the new build here are the test results: 'SHARP AR-5620N' is a network printer '\OFFICE-5\HP LaserJet P2035' is a windows shared printer

win.print({'printer': 'SHARP AR-5620N'}); works fine as intended

win.print({'printer': 'SHARP AR-5620N2'}); uses default printer set in chrome print dialog cuz this printer does not exists, works as intended

win.print({'printer': '\OFFICE-5\HP LaserJet P2035'}); does NOT work but i can use it in print dialog

win.print({'pdf_path': 'C:\asd.pdf'}) does NOT work, does not print to default printer and does not create the pdf in this location, nor any Additional info: I tried the following paths: win.print({'pdf_path': 'C:\Dev'}) win.print({'pdf_path': 'C:\Dev\test.pdf'}) Also If I open the app and i use print to pdf in print dialog, it wokrs fine, but after i use the win.print({'pdf_path': 'C:\asd.pdf'}) the print to pdf function in the print dialog no longer works.

headerFooterEnabled: works fine

landscape: works fine

shouldPrintBackgrounds: works fine

mediaSize: works fine

Windows 10, v0.14.7

rogerwang commented 8 years ago

I tried it with something like E:/1.pdf and it works. Could you please check again with forward slash?

On Thu, Jun 2, 2016, 3:08 PM kailniris notifications@github.com wrote:

Hello, I tried out the new build here are the test results: 'SHARP AR-5620N' is a network printer '\OFFICE-5\HP LaserJet P2035' is a windows shared printer

win.print({'printer': 'SHARP AR-5620N'}); works fine as intended

win.print({'printer': 'SHARP AR-5620N2'}); uses default printer set in chrome print dialog cuz this printer does not exists, works as intended

win.print({'printer': '\OFFICE-5\HP LaserJet P2035'}); does NOT work but i can use it in print dialog

win.print({'pdf_path': 'C:\asd.pdf'}) does NOT work, does not print to default printer and does not create the pdf in this location, nor any Additional info: I tried the following paths: win.print({'pdf_path': 'C:\Dev'}) win.print({'pdf_path': 'C:\Dev\test.pdf'}) Also If I open the app and i use print to pdf in print dialog, it wokrs fine, but after i use the win.print({'pdf_path': 'C:\asd.pdf'}) the print to pdf function in the print dialog no longer works.

headerFooterEnabled: works fine

landscape: works fine

shouldPrintBackgrounds: works fine

mediaSize: works fine

Windows 10, v0.14.7

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/nwjs/nw.js/issues/4911#issuecomment-223212854, or mute the thread https://github.com/notifications/unsubscribe/AAKGGXRFFBdu-iw_2eUlcri5wCpMV3fTks5qHoGCgaJpZM4Ipfyu .

kailniris commented 8 years ago

Confirmed it works with win.print({'pdf_path': 'C:/Dev/test.pdf'})

Could the \ slashes the problem with the "\OFFICE-5\HP LaserJet P2035" printer name?

Another thing i found out if i use the win.print() function the regular print (dialoged one) print to pdf will not work till nw restart.

jasminmif commented 8 years ago

Im trying to print PDF directly to a printer: i run the app in kiosk printing: nw.exe --kiosk-printing ..\

And the only option thats printing is the win.print({}) ( function printDialog() ), others just show the printing Layout just like in chrome, and it gets hidden automaticly and no job to the printer gets sent.

Im running: nwjs-sdk-v0.14.7-win-x64.zip

// Not Working
function printerNamePrint() {
    console.log('printerNamePrint');
    var printerName = "HP LaserJet Professional P 1102w_1";
    win.print({
        printer: printerName, 
        pdf_path: filePath
    });
}
//Not Working
function pritnerDoc() {
    console.log('printerDoc');
    win.print({
        pdf_path: filePath
    });
}
//Working
function printDialog(){
    win.print({});
}
//Working
function printName() {
    win.print({
        printer: "HP LaserJet Professional P 1102w_1", 
    });
}
Andrew-Gee commented 8 years ago

It seems to remember the last printer passed in, and disregards future printer values.

notsospecial1 commented 8 years ago

@rogerwang, @Gimmeaphatbeat, @jasminmif, @kailniris

Custom "Silent" printing -- win.print({options}) seems to be developing nicely. But "normal" (HTML5 print dialog window) printing has been lost..... at least on Windows-32.... hasn't it? Neither win.print() nor win.print({}) allow interaction with the print dialog at this point (in latest nightlys of nw-14x, 15x and 16x).

kailniris commented 8 years ago

@notsospecial1 Try Window.print() for default print dialog.

notsospecial1 commented 8 years ago

@kailniris

" Window.print() is not a function "

kailniris commented 8 years ago

@notsospecial1 Sorry typo. I ment window.print()

notsospecial1 commented 8 years ago

@kailniris

Great !! It works and I can go back and forth between dialoged- and silent- printing. Now I need to figure out exactly why it works (I've never been a fan of naming everything the same in requires, function definitions, etc -- for just this reason).

I assume this has also solved your issue posed above, "Another thing i found out if i use the win.print() function the regular print (dialoged one) print to pdf will not work till nw restart".

Thanks again

kailniris commented 8 years ago

@notsospecial1 I am no expert but the window object is the chrome basic window object. The win object is what you get from var win = nw.Window.get(); so basicly is possible to do monkey.print(obj) too. My problem is a bug. If you use the nw.js save to pdf function you can't save to pdf from the regular print dialog. Try it out.

notsospecial1 commented 8 years ago

@kailniris

Works fine for me ( Win 10 on old 32-bit Win XP => Win 7 => Win 10 Sony Vaio). Incidently, the win.getPrinters(callback) does not find the "save to pdf" choice -- it lists 10 "printers" but the window.print() dialog shows 11 -- including "save to pdf" and allows modification (orientation, etc) before saving to a pdf file. As I mentioned, I can go back and forth between silent- and dialogued- printing with no problems, so far. I will dig further into possible conflicts/glitches as time allows. I am currently testing on the most recent "win-ia32 nw;js 16.0 beta candidate 1" before checking out the most recent 14.x and 15.x builds which are all supposed to include the "Custom" print API.

notsospecial1 commented 8 years ago

@kailniris

Here is my quick-and-dirty index.html file....

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Test Custom Printer extension</title> <script> var win = nw.Window.get(); function pCallBack(printJob) { console.log(JSON.stringify(printJob)); }; var options = {'printer': 'Canon MP970 series Prnter', 'landscape': true, 'headerFooterEnabled': true } ; </script> </head> <body> <input type="button" value="Get Prntrs" onClick="win.getPrinters(pCallBack)"/> <input type="button" value="Silent Print" onClick="win.print(options)"/> <input type="button" value="Normal Print" onClick="window.print()"/> </body> </html>

Actually, dirty it may be, but hardly quick --- it took me 15 minutes to get the code showing....

kailniris commented 8 years ago

@notsospecial1 The getprinters function won't return the savs to pdf 'printer'. If you want to use the savetopdf dialog print option in in win.print you have to use win.print({'pdf_path': 'C:/Dev/test.pdf'}). Use this function to print to pdf to a location on your disk then the regular print to pdf in the print dialog will no longer work.

gerdus commented 8 years ago

The Save To PDF using normal print not working til app restart can be "solved" by running: win.print({'pdf_path': ''}) Which will prompt for a PDF location so isn't a true workaround. Subsequent print to pdf using default dialog works then. Storing the printer settings before the custom printing api call and restoring them after would probably solve this.

notsospecial1 commented 8 years ago

@gerdus

"Storing the printer settings before the custom printing api call and restoring them after would probably solve this."

I have been trying to figure this out.... I presume the "printer" whose "settings" would be stored and restored would be the one utilized for silent printing. But I have no clue as to the storing/restoring code (win 10 -ia32). Are we talking the "preferences" or "properties" as shown in the devices and printers settings? And how is it done programmatically? (i.e. in javascript)? Any clues would be welcome, and thank you for the "pseudo-workaround" solution.

rogerwang commented 8 years ago

To all: I just fixed the "print to pdf" issue in normal print dialog. It will be available in the next nightly build.

@fanchou using 'pdf_path' is supposed to specify the output pdf path when you print the current page...

kailniris commented 8 years ago

@gerdus This is a bit misleading, the only reason why win.print({'pdf_path': ''}) prompts a dialog cuz the last used option in print dialog was savetopdf. If you set a printer in the chrome print dialog then you call win.print({'pdf_path': ''}) then the doc will be printed to the printer you lastly set.

rdtsc commented 8 years ago

@rogerwang: When printing silently (e.g., to PDF or directly to some printer), the Chromium print dialog pops up for a short while and then disappears once the job is spooled. This is the case for Windows, at least.

Silent mode should really be silent without any additional modals spawning. Would it be possible to implement an additional boolean flag like show_print_dialog in win.print that when set to false would forcefully prevent the Chromium print modal from spawning when user interaction is not required?

Currently, a workaround is to spawn another hidden NW.js window and print from there, but that's a little ugly.


Behavior:

Source:
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Print Test</title>
    <style>@media print {button {display: none}}</style>
    <script>
    function printToPdf()
    {
      nw.Window.get().print({pdf_path:'c:/foo.pdf', headerFooterEnabled:false});
    }
    </script>
  </head>
  <body>
    <pre>Lorem ipsum dolor sit amet, consectetur adipisicing.</pre>
    <button onclick="printToPdf()">Print to PDF</button>
  </body>
</html>
jasminmif commented 8 years ago

@rdtsc Does it prints, cause when i use the same code, it does not. Correct me if im wrong but

pdf_path is the path of the PDF File you want to print ?

rdtsc commented 8 years ago

@jasminmif: Maybe I'm misunderstanding your intent. If you want to convert HTML to PDF, then yes, the above works without issue on Windows (at least) using the nightly v0.15.2 build: http://dl.nwjs.io/live-build/06-06-2016/nw15-024592f-5c2963f-0b926c0-c74d4b4/v0.15.2/

If you want to print an existing PDF, then no, the above won't work. I haven't been keeping up to date with NW.js for the past few weeks, so I don't know if this feature has been implemented or is in the pipeline.

jasminmif commented 8 years ago

@rogerwang is there a way to tell a Specific printer Print a PDF document with NW?

dvlsg commented 8 years ago

Seems a bit out of scope to directly print a PDF from the filesystem.

What happens when you try to load the pdf (file:///C:/path/to/your/file.pdf) in a new nw window, then print that window? I haven't tried it, but that might work.

kailniris commented 8 years ago

@rogerwang Can we have margin support please? I created an invoice printer app and everything works flawlesly with the printing api expect that I can't change margin options. I found out in the app Preferences file there is 2 options regarding to this. "marginsType\":3 // 0 is for default margin, 1 is for no margin 2 is for minimul margin, 3 is for custom margin 'customMargins': { 'top': 12, 'right': 12, 'bottom': 12, 'left': 12 }

Can you please upgrade the print api with margin support?

rogerwang commented 8 years ago

@kailniris sure, will add it soon.

kailniris commented 8 years ago

@rogerwang Thanks your very much! I am looking forward to it! I accidentaly created a new issue regarding to this, I hope its not a problem, sorry!

rogerwang commented 8 years ago

The print API now supports printing a PDF file. You can open the PDF file in a new window and print from it.

http://dl.nwjs.io/live-build/06-29-2016/nw15-cc83171-b33fad2-3ee2c58-8655cb9/v0.15.5/

rogerwang commented 8 years ago

@rdtsc I'll see how to hide the print UI but it may not be very easy.

btw, it's exactly upstream issue: https://bugs.chromium.org/p/chromium/issues/detail?id=169004

douglasduartetb commented 8 years ago

@rdtsc I'm having the same problem as you! But using Mac OSX Yosemite v. 10.10.5

acicali commented 8 years ago

The ability to retrieve a list of bin/tray names for each printer as well as print to a specific tray is important to me. I know you're busy @rogerwang! :)

rogerwang commented 8 years ago

@acicali does Chromium browser supports the setting?

acicali commented 8 years ago

@rogerwang, unless I'm mistaken, I don't think it applies. When printing with Google Chrome, the user is provided with the ability to select preferences from a dialog, at least in Windows. It allows the user to "Print using system dialog". That triggers the standard print dialog, which then contains a "preferences" button. I believe the preferences button opens the printer driver's private mode settings.

I'm currently using nwjs v0.11.2 and a custom module to satisfy this requirement. It uses the win32api to fetch a list of printer properties from that standard print dialog, and it is able to retrieve the list of "binNames". I'd be happy to get rid of this dependency though, as I wrote it myself and have very little experience with either c++ or the windows API. I'd also like to upgrade to v.0.14, but I need to get rid of this custom module first.

petermeester commented 8 years ago

Hi, the new printing feature is very nice . We are using it in our application. We developed an application for our delivery partners so they can receive orders from our website which will be automatically printed. Works fine. We can't push multiple printjobs at once because we first create a local PDF file received from our API but we have settle this using a custom function which check every five seconds for new printjobs and execute one printjob at a time (some kind of print queue).

In our application the client can choose a normal A4 printer and a POS printer. We noticed that when a printjob is executed, the default printer on Windows has been changed. Is this a bug in Chromium? When we execute the print function, we defined the printer name. Is there a way to get the default printer and set the default printer again after the printjob has been executed?

See my issue #5300

conceptualspace commented 7 years ago

we're trying to use the print API to hide chrome's headers/footers, but now the print preview pops up briefly and disappears

anybody else seeing this? to be clear, we're trying to customize the print settings but are not looking for silent printing (my understanding is that is provided independently by kiosk-printing flag)

nw 0.19.1; also tried 0.16.4

conceptualspace commented 7 years ago

maybe result of _option["autoprint"] = true;.. can this be exposed as option?

maschinenzeitmaschine commented 7 years ago

after running in circles for quite a while (there are so many threads about printing that all reference each other, it's almost kafkaesque), two questions:

thanks a lot for any help!!! k

in html file: <iframe name="printframe" id="printframe" style="display: none;"></iframe>

in javascript: document.getElementById('printframe').contentWindow.document.write(myString)); window.frames['printframe'].print();

rdtsc commented 7 years ago

@karlkrach: AFAIK, the scriptable printing API only works with NWWindow instances.

You can see some basic sample code in my earlier comment.

As mentioned in my comment, I use a hidden window to work around the brief print dialog popup issue. I've got a Windows app in production that uses something similar to this technique without user complaints:

nwjs-4911-ss

package.json:

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

index.html:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>NW.js Silent Printing Demo</title>
  </head>
  <body>
    <textarea id="payload" placeholder="HTML"></textarea>
    <button id="print">Print</button>
    <script>
      document.addEventListener('DOMContentLoaded', () => {
        const $ = document.querySelector.bind(document);
        const textarea = $('#payload');

        $('#print').onclick = () => {
          const data = textarea.value.trim() || 
            '<img src="https://nwjs.io/img/logo.png">';

          const payload = `data:text/html,${encodeURI(data)}`;

          nw.Window.open(payload, {show: false}, (win) => {
            win.on('loaded', () => {
              const filename = 'result.pdf';

              win.print({
                pdf_path: filename, 
                headerFooterEnabled: false
              });

              win.close();
              nw.Shell.openItem(filename);
            });
          });
        };
      });
    </script>
  </body>
</html>

IIRC, I use Window.postMessage paired with an inject_js_start script (see nw.Window.open) since I have to support like 30 report types based on different templates located on the fs.

For what it's worth, if you need more advanced control over your PDFs, I'd recommend taking a look at wkhtmltopdf provided that it fits your redistributable size allowance, if any.

maschinenzeitmaschine commented 7 years ago

... it did take me some time to understand the magic happening in your code - but since i did, it works really well. again: thank you so much!!

one question left: when printing, the screen briefly freezes for like a second or so - which will not be much of an issue in most of the cases but since i have a continous animation going on, it does look quite irritating. i tried circumventing this by introducing a setTimeout which, according to this link https://javascriptweblog.wordpress.com/2010/06/28/understanding-javascript-timers/ should defer execution to a low priority queue - but that did not do the trick. is there anything i could do about this?

apart, just in case someone else should have the same questions as me:

TheJaredWilcurt commented 7 years ago

May 31, 2016

AndryBray: Just saw electron supports win.printToPDF(options, callback). Any chance to build something like that? rogerwang: it will be included.

Is there a way to run a callback for when a print finishes. If so it isn't documented:

Would it be possible to add this feature, or, if it already exists, have the documentation updated to reflect that.

kailniris commented 7 years ago

@TheJaredWilcurt Is not printing api synchronous?

rogerwang commented 7 years ago

Yeah, it is synchronous so there is no callback...

alexandreprado commented 7 years ago

Hi guys,

Even if I set 'show' to false in the open window options, when I call 'print' to a specific or default printer, the window shows up for a few seconds. I couldn't find a way to keep this window hidden, is there a fix for it or something?

Behavior:

silent printing

Source:

package.json { "name": "JustRestaurante", "main": "index.html" }

index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>NW.js Silent Printing Demo</title>
</head>
<body>
<textarea id="payload" placeholder="HTML"></textarea>
<button id="print">Print</button>
<script>
    document.addEventListener('DOMContentLoaded', function () {
        var $ = document.querySelector.bind(document);
        const textarea = $('#payload');
        $('#print').onclick = function() {
            var data = textarea.value.trim();
            var payload = `data:text/html,${encodeURI(data)}`;
            nw.Window.open(payload, {show: false}, function (win) {
                win.on('loaded', function () {
                    win.print({
                        printer: 'Photosmart_D110_series'
                    });
                    win.close();
                });
            });
        }
    });
</script>
</body>
</html>

I'm using NW.js v0.20.3 SDK on macOS 10.12.3, btw.

Thanks!

maschinenzeitmaschine commented 7 years ago

hi, sorry to ask again but this is becoming quite a problem for me: thanks to rdtsc and his post https://github.com/nwjs/nw.js/issues/4911#issuecomment-277491619 i now do manage to print silently BUT everytime i do so, my whole app freezes for about 4 seconds. is there anything i can do about this? is this because the printing api is synchronous? i did try to run printing from another window but to no avail, it always puts the whole app on hold... thanks for any help with this!! karl