3

I have a Python application taht will be executed repeatedly. It saves a PDF as a file and then prints it. When printing ends it deletes the file.

My current solution (for the print and delete part) is this:

win32api.ShellExecute(0, "print", file_path, None,  ".",  0)
time.sleep(10)
os.remove(self.options.dest_name)

time.sleep(10) is a trick to give the printing process the time to run before file deletion. Without it Acrobat Reader opens (it opens anyway) and alerts that it can't find the file. This because file removal has already occured.

The question is:

  1. how can I do it without this unreliable trick? The best thing would be to have an handler for the printing process and get by it an info about the printing state: I wait for it to report it's completed and I delete the file.

  2. it would be even better if Acrobat Reader wouldn't open, but this is not a great problem.

EDIT: I tried switching to Foxit Reader as the default PDF reader and now it doesn't open when I don't want. ;)

OTHER POSSIBLE SOLUTION: Cylically check if the file is available (not used by another process) and when it's available again delete it. How could I do it in Python?

bluish
  • 26,356
  • 27
  • 122
  • 180
  • 3
    Honestly, there's no real way to know if something *actually* printed. There are 100 different problems that can happen in the print queue that will never get reported back to you. – Nick Bastin Dec 17 '10 at 12:04
  • @Nick Mhm, let's say I only need to know when the document has been sent to the printer. So I can throw it away. – bluish Dec 17 '10 at 12:37

4 Answers4

4

At last I've found a good solution, thanks to this answer (and also @Lennart mentioned it on a comment):

install Ghostscript

install GSview (which includes gsprint.exe)

write this code:

file_path = "C:\\temp\\test.pdf"
p = subprocess.Popen(["C:\\Ghostgum\\gsview\\gsprint.exe", "-printer", printer_name, "-colour",  file_path],
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate() # waits for the gs process to end
os.remove(file_path) # now the file can be removed

No Acrobat windows opening, no file removed before printing... The annoyance: installing GS.

See also: gsprint reference

Community
  • 1
  • 1
bluish
  • 26,356
  • 27
  • 122
  • 180
2

Rather than hard-coding a filename and printing that, you should use the tempfile module to create a temporary file with a unique name.

import tempfile
file_name = tempfile.NamedTemporaryFile(suffix=".pdf", delete=False)

If you want, you can run a regular tidy-up script using Window's scheduling tools to delete the files created.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • You're right, but in my case selecting a command-line parameter the user can choose to print or save the document. So I prefer saving it as a file and, if the user decided to print and delete it, doing this operations. – bluish Dec 17 '10 at 12:45
1

Adobe acrobat has (or at least used to have) a parameter "/t", which made it open, print and exit. By using it, you can call acrobat reader and wait for it to exit, and then delete the file.

Untested code:

>>> import subprocess
# You will have to figure out where your Acrobate reader is located, can be found in the registry:
>>> acrobatexe = "C:\Program Files\Adobe\Acrobat 4.0\Reader\AcroRd32.exe"  
>>> subprocess.call([acrobatexe, "/t", tempfilename, "My Windows Printer Name"])
>>> os.unlink(tempfilename)

Something like that.

If you don't want acrobat to open, there are open source software that will print pdfs from the command line. You could include one with your software.

Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
  • Thanks! The open source sw you say, are them something I can import in my python program? Can you suggest one of them, please? – bluish Dec 17 '10 at 12:48
  • 1
    Not import, maybe, but call at least. You can certainly do it with Ghostscript, but that's a pretty big program, you might find better ones. I'm no expert on that topic. You can ask another question, or ask Google. :) – Lennart Regebro Dec 17 '10 at 12:57
0

Why not use os.system, which will wait until the process is finished?

JasonFruit
  • 7,764
  • 5
  • 46
  • 61
  • @Jason In which way? How can I indicate that specific process I started with win32api.ShellExecute(...)? – bluish Dec 17 '10 at 13:44
  • I mean, use os.system(command) to start a process that does the print instead of using win32api.ShellExecute. It will wait until the process is complete and then return its exit code. – JasonFruit Dec 17 '10 at 13:55
  • (I see I misunderstand win32api.ShellExecute.) For example, you could use os.system to start Adobe Reader with Lennart's /t switch. – JasonFruit Dec 17 '10 at 13:58
  • I found this: acrobat_path = '"C:\\Program Files (x86)\\Adobe\\Reader 10.0\\Reader\\AcroRd32.exe"' followed by os.system(acrobat_path + " /p /h " + self.options.dest_name). But I need to runtime retreive Acrobat path and user needs Acrobat installed. – bluish Dec 17 '10 at 16:33
  • Here's a link to a Windows batch file that purports to print any file using its associated program from the registry: http://www.robvanderwoude.com/files/printany_nt.txt – JasonFruit Dec 17 '10 at 16:41