Jumat, 17 Agustus 2018

Direct Print to POS Printer from Javascript on Client Side

As you have already known, web browser is like a sandbox. It is not allowed to access anything else on PC. That means, we need a program or background service as an interface to send the data from the web to printer. mike42 provides perfect PHP library that allows direct print from PHP. Unfortunately, PHP is on server side. We still need this library, since mike42 provides us functions that return ESC/POS data in binary. This data is what we need.

Next, since we want to print from web on client side, we need a way to direct print from javascript and, as I mentioned above, a third party service that allows us sending data to the printer. For that purpose, Kwickpos has that program written in python.

I use POS Printer Taffware ZJ-5890K. It is a low-priced thermal POS Printer and it is a good printer.

These are what we need for the PC on client side:

  1. KwickPython, you can download it from its web or download the script here
  2. install Python. Go googling, download and install the latest version
  3. Install Pywin32. Find the version that is compatible with your Python's version
  4. Install the driver of the POS Printer and share it as "POSPRINTER". You can refer to this tutorial if you have never shared printer before.
  5. After installing all of them, you need to add python's file path to Environment Variables. You can read it here. I'm using windows 8 and tested it in windows 10 too, the file path to python is C:\Users\[username]\AppData\Local\Programs\Python\Python37-32. Replace "[username]" with the real path on your PC. 
Do these steps:
  1. Open cmd console by Winkey-R, type "cmd" and Enter
  2. Make KwickPython cgi-bin directory:C:\KwickPython\htbin
  3. Save KwickPython script as:C:\KwickPython\htbin\kp.py
  4. Start the KwickPython:C:\KwickPython> python -m http.server --cgi 9100
Actually, you can read the more detailed explanation in KwickPython website. The script can do some other things, like return the list of active Printer, so you can choose which printer you want to use. My focus in this post is just how to use it for printing.

I assume, you have already started the KwickPython right now. The script listen to port 9100, you may change the port number if you like.

On Server Side you need mike42 PHP Library, download it here.

I forget to mention earlier, that I'm using CodeIgniter. I put the mike42 PHP Library inside the directory "view". And here are the controller and the view for printing.

Controller:

public function printPOS()
{
 $this->load->view('escpos-php-development/autoload.php');
 $this->load->view('print');
}

escpos-php-development is the name of the directory where library located.
Now here is how the "print.php" looks


print.php:
<?php
use Mike42\Escpos\Printer;
use Mike42\Escpos\PrintConnectors\DummyPrintConnector;
use Mike42\Escpos\CapabilityProfile;

/* Open the printer; this will change depending on how it is connected */

try
{
 $connector = new DummyPrintConnector();
 $profile = CapabilityProfile::load("TSP600");
 $printer = new Printer($connector);

 
 $printer -> text("hallo, direct Print From Javascript\n");
 $printer-> feed(3);

 $data = $connector -> getData();
 $base64data=base64_encode($data);
 $printer -> close();
}
catch(Exception $e)
{
 echo "Couldn't print to this printer: " . $e -&gt getMessage() . "\n";
}
?>
<input type="hidden" id="rawdata" value="<?php echo $base64data;?&gt">


<script>
var dat="";
window.onload = callFunction();

function callFunction()
{
 setInterval(ajax(),500);
}

function ajax()
{
 var rawdat=document.getElementById('rawdata').value;
 var xhttp = new XMLHttpRequest();
   
 url = 'http://localhost:9100/htbin/kp.py';
 xhttp.open("POST", url, false); //browser has to wait until the data finished loaded
 xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
 xhttp.onreadystatechange = function(){
  if(this.readyState==4 && this.status == 200)
  {
   alert(this.responseText);   
  }
  
 }
 
 xhttp.send("p=POSPRINTER&data="+rawdat);
}
</script>

Take a look at the ajax function when it call xhttp.send("p=POSPRINTER&data="+rawdat). the "p" is for the name of the shared Printer, you may change the value of  "p". The "data" is the  bas64 encoded binary data of raw ESC/POS commands.

If you are using chrome, you need to install CORS extension. You need it, because the ajax tries to open a url outside the web application domain. Your web domain may be myweb.com and the ajax will try to access localhost, which is outside myweb.com domain. It may lead to security issues, chrome will warn you by the time you are activating this extension.

Actually that is already everything. You may have some question how to start the KwickPython on window startup or how to start it as windows service, just refer to the KwickPython website and just google to find how to start the script as windows service.

I hope this posting can help you somehow.

[Updated]
RUN KwickPython as a Service

To be able to print on client side, you should activate the KwickPython. On the official Website of KwickPython they already told us that there are two ways to start it automatically. Call it as a job and it will activate the cmd console or call it as service with no cmd console. The main problem if you call it as a job, the service will stop if the console is closed. So, its better if the service keep running although the console is closed. Then we should run it as a service. Unfortunately, it is not that easy to execute a command as a service.

So this is how I do it. I run the KwickPython at the startup as batch job with no console.

  1. There are 3 Files that I need: kp.py that I put inside 'htbin' directory, a bat file to execute the command activating the python service and a vbs file to call the bat file without console.
  2. Download the kp.py and put it inside 'htbin' directory
  3. put the htbin inside c:\KwickPython (like I mentioned above)
  4. Create a bat file and give a name, in my case I name it 'printService.bat'. Write this code:
c:\
cd c:\KwickPython
python -m http.server --cgi 9100

  1. Put the printService.bat fie inside c:\KwickPython
  2. Open Run dialog with win+R and type 'shell:startup'. It will open startup directory, every program that you put inside this directory will be activated at the startup windows.
  3. Create a vbs file inside this directory. I name this file 'printService.vbs'. Write this code inside the file
Dim WinScriptHost
Set WinScriptHost = CreateObject("WScript.Shell")
WinScriptHost.Run Chr(34) & "C:\KwickPython\printService.bat" & Chr(34), 0
Set WinScriptHost = Nothing

That's it. Try to reboot your windows. After your windows finish booting, open cmd and check it using 'netstat -tan' whether port 9100 is already in Listening state. Try to print something. It works fine in my project.

I hope this can help you....