Tuesday, May 22, 2012

Printing to a Windows Printer from Gnu/Linux without Linux drivers

As usual I post very few, because the time is very short, but has today I made an achievement I was looking to a long time, it deserves a HOW-TO...

Here it goes....

The Problem:

Our office only has one central printer!! (well it has other, but our boss don't wanna buy tonners, I warned him on the buy, that the 2000€ was better buy, but 600€ looked better in that moment.... no comments). This printer we use is a Windows Printer, which means the developer only has drivers for windows. So no Postscript drivers available, what means a great PITA for our PC's with Linux. So since our 600€ printer went out of service me and 3 other colleagues had to bother one of the other windows users every time we needed to print something.
As this don't look a problem, imagine the hours that are lost.... And we are all engineers.... There are better ways to spend the money with our time.... So I decided to do it.... I had tried before with REDMON (http://pages.cs.wisc.edu/~ghost/redmon/index.htm), but with no success, but this time I made a decision to loose a few hours and make it...

The Solution:

So what I had in mind, was a simple solution.... To have a service running in our Windows SBS2003 that would monitor some folder change, where we would put PDF files and then print them.
Linux handles PDF nice, and the users would print to PDF and then place the files on that folder.
It looked really nice and as I thought a lot of free software was available, but......


To begin I needed a command, from command line that would execute the print command, and after trying it with Acrobat Reader, I realized that it will always leave one window open with the program, and I didn't wanted that. So I had to find another solution.....

Then I needed the software to watch the folder changes.... From a dozen windows software the best one, that was able to execute anything on changes was Watch 4 Folder 2.3 (http://leelusoft.blogspot.pt/), but it didn't worked as expected, and I realized that it would only work on file changes from MS computers. After a few emails with the developer, and as I suspected, it uses the Microsoft Windows Shell API Notifications, and it is not relieable on network shares! Thank you for the support Mr. Zvika Israeli!!!!
So I had to find another solution....

The Deeper Research:

I had bumped into this website HOWTO - Print to a windows printer from linux WITHOUT needing any linux printer drivers/PPDs  (http://justin.yackoski.name/winp/ ) but the python looked a more complicated solution and I had gone to the software in Tryouts chapter :). This webpage has a python script that does what I wanted, but one link in this site was more what I wanted, http://tgolden.sc.sabren.com/python/win32_how_do_i/watch_directory_for_changes.html.

So I grabbed all this info, a lot, and i mean, a lot of python reading..... Especially on string and list manipulation, and came with this solution....

The Solution: (for those in a hurry, please start reading here!!!)

What you need:
1 - A computer running windows
2 - The printer you want to print to must be the preferred printer

Software you need to install on windows machine:
1 - Python - http://www.python.org/ftp/python/2.7.3/python-2.7.3.msi
2 - Pywin32 - http://sourceforge.net/projects/pywin32/files/pywin32/Build%20217/pywin32-217.win32-py2.7.exe/download - This is needed for handling command line file execution, there are other ways to do it, and they make it a lot faster, but as I'm a beginner in Python, it worked this ways, so let it be, maybe in the future I could make my script better
3 - Pdf X-Change Viewer - http://www.tracker-software.com/product/pdf-xchange-viewer - It is freeware even for commercial use (we use it around the office) and it closes after printing from command line

Changes you need to make to the windows machine:
1 - Add c:\Python27 (or the folder you installed Python) and C:\Python27\lib\site-packages\win32 to the system path - How to it http://www.windowsitpro.com/article/configuration/how-can-i-add-a-new-folder-to-my-system-path-

2 - Create the print batch file - Open a notepad and call it print.bat and save it on c:\, fill it with the following code:

"C:\Programas\Tracker Software\PDF Viewer\PDFXCview.exe" /print %1

Note: The path to the executable depends on your system, this is the path to a Portuguese Windows SBS2003!!!!!!!!!

3 - Create the python script file - Open a notepad and call it dirwatch.py (or other name you want) and save it on c:\ and fill it with the following code:

import os, time
import win32api

path_to_watch = "z:\\zz_Scanner\\Imprimir" ##This is the folder where you want to put the files for printing double slash are needed because the slash is a special caracter in python!!!!
before = dict ((f, None) for f in os.listdir (path_to_watch))
while 1:
  time.sleep (1)
  after = dict ((f, None) for f in os.listdir (path_to_watch))
  added = [f for f in after if not f in before]
  removed = [f for f in before if not f in after]
  if added:
      cmd = str("print.bat "+ "\"" + path_to_watch + "\\" + " ".join (added)+"\"")
      print cmd
  before = after

4 - Now run the dirwatch.py and one command line will open without any info. If you place a PDF in the path_to_watch dir, you will see the script finding the file, executing the command and exiting the batch file, and waiting for another file.
The script uses about 5Mb of Ram, and if you want to get less cpu usage you can replace time.sleep(1) for a higher value. The value is seconds so now you choose how much time you want to wait for the printing and balance it with your server load.

5 - I wanted this script to run as a service (seamless) so I place a link to it on startup.
If you don't want to have a command line floating around your server, rename the dirwatch.py to dirwatch.pyw
If you get more then one print, just close python instances on Task Manager.

Future Improvements:

1 - Get rid of win32api to run commands, I'malmost sure that this could be done with os, help please!!! It would execute faster with less Ram usage. And without the need to have pywin32 installed.
2 - Compare also with existing filenames, because a user could replace a file with the same name and the script only recognize files added!!!
3 - Delete the file after printing (if I do this I don't need the point above)
4 - Configure cups-pdf on Linux computer to place files directly on desired directory - I have to deal with file permissions on both linux machines and our NAS server where the folder is.....

So this is it, it worked for me, and a lot can be done so this work better, but the solution is simple and easy, and it will help us to gain time more then important on other tasks....


  1. Why do you call a batch file that calls an executable instead of calling the executable directly?
    The before after trick doesn't seem clean enough -
    How about printing all files that you find then moving them in a subdirectory?
    What if this script starts printing a big pdf before the Linux client is done creating it? At least add a delay after seeing a new file - Better yet I'd you wait until the newly seen file has a stable length for half a second

    1. Your comment is very constructive, thanks a lot.
      But as I wrote, my knowledge in Python is almost zero and I adapted a previous existing code in the link, this was a 1st version of the solution.

  2. Hats off to this Linux ( Real) Engg . :-) Do well. I appreciate. Such small things lock us in propitiatory technology and increase cost world wide. Even for EDUCATION in thrid world countries !!!

  3. I love it,Excellent article.I am decide to put this into use one of these days.Thank you for sharing this.To Your Success!
    indian designer sarees

  4. Just for the record, the script keeps running on server since day one, zero fails!!!

  5. It is really important in an office to have printer which help you print all important documents and files and if you have an issue about your printer then do solution to fix it as possible because this will affect your work.

    Laminate Creasers

  6. What a great post. I need a Plastic card printing machine for home use. Where i can get the best one?

  7. it is a great post and it helps alot. however, when i tried to run the dirwatch.py under windows 7. i got an error about the "cmd", i changed it to "print_cmd" and it goes well. and if possible can you program check the file extension with ".pdf". also, in linux size, user should config the cups-pdf directs its output the "path_to_watch".

  8. i have an idea, you can set up a pdf printer (e.g. bullzip's pdf printer), redirect the output to the path_to_watch. this way, a linux machine can print any file to the pdf printer.


Made in Portugal