Jump to content

Recommended Posts

  • Moderators

I need to print receipts from a webpage (intranet). The difficulty is not so much to get a print happening on some printer, but to do it in such a way that the usual printer selection dialog gets bypassed. So basically a form with a print button which, when pressed, prints a receipt to a designated printer straightaway, without every time asking the user to select a printer.

The normal print methods (window.print(), google cloud print, external print.js libraries) do not solve that problem.

The only reference I found that might work is the ePOS_SDK from Epson, which can be used with some of their receipt printers. See https://www.epson.com.au/pos/products/software/index.asp which lists sdk versions for iOs/Android, but also for webapps / javascript.

If someone has solved a similar problem then feedback is appreciated.

 

Link to post
Share on other sites
  • Moderators

Printers used to be dumb peripherals. Not so with the latest receipt printers (epson).

They have actually an apache webserver built in, and the printer can act as the hub for displays, scanners and other (dumb) peripherals.

Capture.PNG

amazing.

Connecting them to Smart looks like not too difficult.

 

Link to post
Share on other sites
  • Moderators

Edited. And then there is IPP : Internet Printing Protocol
This protocol allows direct access to networked printers, ask for their capabilities, prepare print jobs, manage print queues, execute print jobs and get results.

Exactly what I was after.

I read through the documentation on the website of "The Printer Working Group", which looks after the standardisation of this protocol. 
(http://www.pwg.org/ipp/ippguide.html).

To actually use this protocol, there are various IPP client libraries available (C, Java, Python). 
Fortunately there is a node.js variant as well (https://github.com/williamkapke/ipp).

Both these links give some examples on how to use IPP in real world situations
However the code examples on both sites contain many errors. 
Amazing.

On the plus side, apparently some 98% of all networkable printers have an IPP driver installed by default, and should be adressable this way.
To test this all out, I selected a printer on my network.

The first thing to find out is the identification of the printer.

IPP has its own protocol : ipp(s)://<printer uri> where the printer uri is the printers ip address followed by a path. 
Example : ipp://192.168.1.233/ipp/print
Behind the scenes all traffic is actually routed over http(s), and printer uri's can also be specified as http over port 631. 
Example : http://192.168.1.233:631/ipp/print

The ip address can usually be found in the OS printer settings somewhere and the path is mostly standardised to be just '/ipp/print'  

Not too bad. 
After installing the node.js ipp library (npm install ipp) the following node.js code queries the printers capabilities

var ipp = require("ipp");
var printer = ipp.Printer("http://192.168.1.233:631/ipp/print");

var msg = {
  "operation-attributes-tag": {
    "requesting-user-name": "John Doe",
    "document-format": "image/pwg-raster",
    "requested-attributes": ["printer-description", "job-template", "media-col-database"]
  }
};

printer.execute("Get-Printer-Attributes", msg, function(err, res) {
        console.log(err);
        console.log(res);
});

This produces quite a list.

To print a textfile to this printer, I got this code working

var ipp = require("ipp");
var printer = ipp.Printer("http://192.168.1.233:631/ipp/print");
var fs = require("fs");

fs.readFile("example.txt", function(err, content) {            
  if (err) throw err;

  var msg = {
    "operation-attributes-tag": {
      "requesting-user-name": "John Doe",
      "document-format": "application/octet-stream"         
    },
    data: content
  };

  printer.execute("Print-Job", msg, function(err, res) {
        console.log(err);
        console.log(res);
  });

});

 

Edited :

The javascript sources above can be produced by a regular smart project : create a new node project and replace unit1 with

unit Unit1;

interface

uses nodeBasics;  //https://forums.smartmobilestudio.com/topic/4652-node-ground-zero/?tab=comments#comment-23115

type
  TNodeProgram = class(TObject)
  public
    constructor Create; virtual;
    ipp, msg, printer : variant;
    procedure   callback(err, res: variant);
    procedure   Execute;
  end;

implementation

constructor TNodeProgram.Create;
begin
  inherited Create;
  ipp := RequireModule('ipp');
  printer := ipp.Printer("http://192.168.1.233:631/ipp/print");

  msg := new JObject;
  asm
  @msg = {
    "operation-attributes-tag": {
      "requesting-user-name": "John Doe",
      "document-format": "image/pwg-raster",
      "requested-attributes": ["printer-description", "job-template", "media-col-database"]
    }
  };
  end;
end;

procedure TNodeProgram.callback(err, res: variant);
begin
  console.log(err);
  console.log(res);
end;

procedure TNodeProgram.Execute;
begin
  printer.execute("Get-Printer-Attributes", msg, @callback);
end;

end.

 

note unfortunately we can't make up anonymous classes with hyphens in the classname, otherwise the msg variable could have been constructed as

var msg = class
  operation-attributes-tag = class
    requesting-user-name = "John Doe",
    document-format = "image/pwg-raster",
    requested-attributes : array[0..2] of string =
      ["printer-description", "job-template", "media-col-database"];
  end;
end;

 

Next step is to see if this can be made to work in the browser as well 

 

Link to post
Share on other sites
  • Moderators

Edited. The final piece of the puzzle is to find out if it is possible to use IPP printing directly from the browser, bypassing the need for a node server.
The answer, surprisingly, is that it is possible. There are some caveats, but essentially it can be done.

First thing is to get the node.js project and transform it into something a browser understands.
The way to do this is to use Browserify, which will bundle the project file, the ipp library and all of its dependencies :

  • install browserify (npm install browserify)
  • Save the first node.js code example of the previous post (the code which lists printer capabilities) to file, say 'ipp.js'
  • Execute 'browserify ipp.js -o bundle.js'. This produces a 'bundle.js' file which incorporates everything the browser needs.

The minimum html file with a reference to this file included :

<!doctype html>
<html>
  <head>
    <title>Browserify</title>
  </head>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

Executing this should produce the list of printer capabilities.

However it doesn't and a CORS error occurs. In short : essentially scripts calling other scripts (which happens here) is forbidden if these scripts are not on the same origin (domain). CORS is a method to relax that, but it requires the non-origin server to send a specific header in its response (Access-Control-Allow-Origin). If not, browsers will throw an error.

Apparently the ipp library doesn't handle this CORS requirement.
The only way to circumvent this is to either use a proxy server (see article link) or to instruct the browser to disregard same origin checking alltogether.

The latter option involves firing up a separate Chrome instance with some switches :

start chrome --args --disable-web-security --user-data-dir="C:\chrome_temp" file:///C:/Users/...../print/test.html

Works for me. Executing the html file above generates the expected output.

 

Edited :

If the app is produced using Phonegap/Cordova apparently it is possible to handle CORS by whitelisting the various origin domainnames. Have not tried that. 

 

Is IPP worth the trouble ? I think so if the use-case is what started this post : having to print from a webpage (intranet) without having to go through a printer selection dialog every time a print is initiated. In my case dealing with a retail ePos application where every transaction needs a printed docket.

Afaik the only other option is to use specialised printers like the ones in the epson family.

 

 

 

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...