Python silent print PDF to specific printer

Question:

I have a PDF document and I want to print it with my python app.

I have tried the solution in here (Print PDF document with python’s win32print module?) but when I install Ghostscript 9.15 that is the actual version, it has no gsprint.exe

The way I am using that works is with the command os.startfile('PDFfile.pdf', "print") but it opens default viewer (mine is Adobe Reader) and after printing it stills open, trying to kill the process with os.system("TASKKILL /F /IM AcroRD32.exe") kills other opened windows and I dont want it.

With the next command, it also prints, but it let the Adobe Reader opened too

currentprinter = win32print.GetDefaultPrinter()
win32api.ShellExecute(0, "print", 'PDFfile.pdf', '/d:"%s"' % currentprinter, ".", 0)

I have seen this answer too but they recommend using gsprint.exe again

Anybody has the gsprint.exe file or any other solution?.

NOTE: When I used another default program to open PDF files like Chrome or Windows Reader, I always get an Exception in the execution of the commands above '(31, 'ShellExecute', 'A device attached to the system is not functioning.')' or [Error 1155] No application is associated with the specified file for this operation: 'PDFfile.pdf' with the startfile command

Asked By: Alex Lord Mordor

||

Answers:

Finally after hours and hours of searching for the right files, i have found the answer to my problem.

You can download the GSPRINT in HERE

You can download the Ghostscript GPL in HERE

With this extracted files in your PC (Windows) you can print your PDF with this command

GHOSTSCRIPT_PATH = "C:\path\to\GHOSTSCRIPT\bin\gswin32.exe"
GSPRINT_PATH = "C:\path\to\GSPRINT\gsprint.exe"

# YOU CAN PUT HERE THE NAME OF YOUR SPECIFIC PRINTER INSTEAD OF DEFAULT
currentprinter = win32print.GetDefaultPrinter()

win32api.ShellExecute(0, 'open', GSPRINT_PATH, '-ghostscript "'+GHOSTSCRIPT_PATH+'" -printer "'+currentprinter+'" "PDFFile.pdf"', '.', 0)

The GhostScript can also be found in the Official page HERE

I found the gsprint.exe for 64bits HERE

I hope this helps.

Answered By: Alex Lord Mordor

Here’s a way to silently print a pdf in the same directory as your python script without gsprint and without win32api. It allows for more GhostScript customization like choosing width/height, etc.

import os
import subprocess
import sys

if sys.platform == 'win32':
    args = '"C:\\Program Files\\gs\\gs9.23\\bin\\gswin64c" ' 
           '-sDEVICE=mswinpr2 ' 
           '-dBATCH ' 
           '-dNOPAUSE ' 
           '-dFitPage ' 
           '-sOutputFile="%printer%myPrinterName" '
    ghostscript = args + os.path.join(os.getcwd(), 'myFile.pdf').replace('\', '\\')
    subprocess.call(ghostscript, shell=True)

If you’re using the 32 bit version of GhostScript then you would use gswin32c

Answered By: bdoubleu

If you want to print specific pages and some other parameters, you should specify them in the parameters of gsprint as follows:

import win32print
import win32api

GHOSTSCRIPT_PATH = "C:\path\to\GHOSTSCRIPT\bin\gswin32.exe"
GSPRINT_PATH = "C:\path\to\GSPRINT\gsprint.exe"

params = '-ghostscript "'+ GHOSTSCRIPT_PATH  +'" -printer "'+currentprinter+'" -from 1 -to 3 -landscape -copies 1 "1.pdf "'
print(params)

win32api.ShellExecute(0, 'open', GSPRINT_PATH, params, '.',0)
Answered By: Mohammad

The following code will block the current task

for i in range(10):
    currentprinter = win32print.GetDefaultPrinter()
    win32api.ShellExecute(0, "print", 'PDFfile.pdf', '/d:"%s"' % currentprinter, ".", 0)

and killing the reader after printing help won’t block the current task

os.system("TASKKILL /F /IM AcroRD32.exe") 

but it will close other pdf files too.

If you can’t use gsprint, use the acrobat command

import win32print
import subprocess
import time
pdf_file  = 'D:d1d1.pdf'
acrobat = 'C:Program Files (x86)AdobeAcrobat Reader DCReaderAcroRd32.exe'
name = win32print.GetDefaultPrinter()
cmd = '"{}" /n /o /t "{}" "{}"'.format(acrobat, pdf_file, name)
for i in range(10)):
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

It won’t block the current task and close the other pdf files.

Answered By: Jisson

I know this is an old question, but in case someone is looking for it here is how I fixed it.

I am using python 3.8 and gs9.52 on windows 10 64-bit and python3-ghostscript library which you can install using pip install python3-ghostscript I am also using pypiwin32 to get the default printer name, you can install it with pip pip install pypiwin32

This is the working script

import tempfile
import win32print
import locale
import ghostscript
import render_to_pdf

pdf = render_to_pdf('print/slip.html', context)
temp1 = tempfile.mktemp('.pdf')
f1 = open(temp1, 'ab')
f1.write(pdf)
f1.close()

args = [
        "-dPrinted", "-dBATCH", "-dNOSAFER", "-dNOPAUSE", "-dNOPROMPT"
        "-q",
        "-dNumCopies#1",
        "-sDEVICE#mswinpr2",
        f'-sOutputFile#"%printer%{win32print.GetDefaultPrinter()}"',
        f'"{temp1}"'
    ]

encoding = locale.getpreferredencoding()
args = [a.encode(encoding) for a in args]
ghostscript.Ghostscript(*args)

Few things to note here I am using ‘#’ instead of ‘=’ because for some reason it was not working with ‘=’.

If this is not working for you try changing -sDEVICE switch to your printer type for example when I was using HP LaserJet it was giving me prompt so I changed my -sDEVICE to laserjet and it worked, you can get the list of device by running gs -h in terminal

Answered By: wetler

So this isn’t exactly silently, but it will automatically dismiss the dialog box and print anyway, also has a weird dependency on selenium that you wouldn’t expect per se, but this actually worked for me since I was in a world where I wasn’t allowed to download ghostscript nor could I download adobe’s pdf reader. I thought it might help someone else out there, somewhere, some place, some time…

from selenium import webdriver
import win32com.client
import win32print
import time

def printpdf(pdf,printer):
    current_printer = win32print.GetDefaultPrinter()
    win32print.SetDefaultPrinter(printer)
    driver = webdriver.Chrome()
    driver.get(pdf)
    time.sleep(1) #Adjust as necessary
    shell = win32com.client.Dispatch("WScript.Shell")
    shell.SendKeys('^p')
    time.sleep(1) #Adjust as necessary
    shell.SendKeys('{ENTER}') #dismiss the print dialog box
    driver.close()
    win32print.SetDefaultPrinter(current_printer)
    

    
Answered By: Ryan

Based on previous answers and other posts, i develop the following script to print .pdf and .ps from a Laravel website.

I used python 3.9 and Ghostscript 9.54 (for 64bits). pywin32 and python3-ghostscript libs are requiered too.

import os
import sys
import win32print
import win32api
import ghostscript
import locale

USELESS_PRINTER = ['OneNote for Windows 10', 'OneNote (Desktop)', 'Microsoft XPS Document Writer',
                   'Microsoft Print to PDF', 'Fax']

HELP = """pyPrinter - Author: Arthur SICARD - Date: 19/05/2021
n-help
tDisplay this message.
n-list [-virtual]
tReturn list of available printer (excepted: """ + ", ".join(USELESS_PRINTER) + """)
n-file filepath [-printer printer_name] [-virtual]
tPrint specified file on default system printer. Use -printer to specify printer to use. Printer name must be available un -list response.
n-batch filepath [-printer printer_name] [-virtual]
tPrint each document specified un batch file on default system printer. Batch file must be a .txt. Each file to print must be write on its own line.
tUse -printer to specify printer to use. Printer name must be available un -list response.
n-virtual
tUse this option after all other arguments to enable printing on virtual printer 'Microsoft Print to PDF'
"""


# Safe accessor to argv. Return None if index is not set
def getArgv(index):
    try:
        return (sys.argv[1:])[index]
    except:
        return None


# Return list of local printer available without "virtual printer" define in USELESS_PRINTER list.
def getAvailablePrinters():
    printers = win32print.EnumPrinters(win32print.PRINTER_ENUM_LOCAL)
    printer_list = []
    for x in range(len(printers)):
        if printers[x][2] not in USELESS_PRINTER:
            printer_list.append(printers[x][2])
    return printer_list


# Return printer name to use. If -printer is set it will return this value only if value match with available
# printers list. Return a error if -printer not in list. If no printer specified, retrieve default printer and return
# its name. Sometime default printer is on USELESS_PRINTER list so first printer return by getAvailablePrinters() is
# return. If no printer is return display an error.
def getPrinter():
    default_printer = win32print.GetDefaultPrinter()
    if default_printer in USELESS_PRINTER:
        if len(getAvailablePrinters()) == 0:
            print("No printer available, unable to print. Use -virtual if you want enable virtual printer.")
            sys.exit(1801)
        default_printer = getAvailablePrinters()[0]
    if getArgv(2) is not None:
        if getArgv(2) == "-printer":
            printer = getArgv(3)
            if printer in getAvailablePrinters():
                return printer
            else:
                if printer is not None:
                    print("Given printer not found. Defaut printer configured: ", default_printer)
    return default_printer


# Use GhostScript API to silent print .pdf and .ps. Use win32api to print .txt. Return a error if printing failed or
# file ext doesn't match.
def printFile(filepath):
    try:
        if os.path.splitext(filepath)[1] in [".pdf", ".ps"]:
            args = [
                "-dPrinted", "-dBATCH", "-dNOSAFER", "-dNOPAUSE", "-dNOPROMPT"
                                                                  "-q",
                "-dNumCopies#1",
                "-sDEVICE#mswinpr2",
                f'-sOutputFile#"%printer%{getPrinter()}"',
                f'"{filepath}"'
            ]

            encoding = locale.getpreferredencoding()
            args = [a.encode(encoding) for a in args]
            ghostscript.Ghostscript(*args)
        elif os.path.splitext(filepath)[1] in [".txt"]:
            # '"%s"' % enable to encapsulate string with quote
            win32api.ShellExecute(0, "printto", '"%s"' % filepath, '"%s"' % getPrinter(), ".", 0)
        return True

    except:
        print("Printing error for file: ", '"%s"' % filepath, "| Printer: ", '"%s"' % getPrinter())
        return False


def main(argv):
    if len(argv) in [1, 2, 4, 5]:
        cmd1 = getArgv(0)
        filepath = getArgv(1)

        if argv[-1] == "-virtual":
            USELESS_PRINTER.remove('Microsoft Print to PDF')

        # Batch printing mode
        if cmd1 == "-batch" and len(argv) in [2, 4, 5]:
            if not os.path.isfile(filepath) and not os.path.exists(filepath):
                print("Path provide for batch file is not a valid file path or doesn't exist.")
                sys.exit(2)
            if os.path.splitext(filepath)[1] in [".txt"]:
                with open(filepath) as fp:
                    line = fp.readline().strip('n')
                    while line:
                        if not os.path.isfile(line) and not os.path.exists(line):
                            print("Path provide is not a valid file path or doesn't exist: ", line)
                        else:
                            printFile(line)
                        line = fp.readline().strip('n')
                fp.close()
            else:
                print("Not supported file format for batch printing.")
                sys.exit(50)

        # Single file printing mode
        elif cmd1 == "-file" and len(argv) in [2, 4, 5]:
            if not os.path.isfile(filepath) and not os.path.exists(filepath):
                print("Path provide is not a file path.")
                sys.exit(2)
            if not printFile(filepath):
                sys.exit(1)

        # Get printers list
        elif cmd1 == "-list" and len(argv) in [1, 2]:
            for printer in getAvailablePrinters():
                print(printer)

        # Display help
        elif cmd1 == "-help" and len(argv) in [1]:
            print(HELP)
            sys.exit(0)
        else:
            print("Unknow option. Use -help to obtain more informations about supported options.")
            sys.exit(50)
    else:
        print("Wrong arguments number. Use -help to obtain more informations about supported options.")
        sys.exit(50)
    exit(0)


if __name__ == '__main__':
    main(sys.argv[1:])

Following command explain how to use it:
python main.py -help

pyPrinter - Author: Arthur - Date: 19/05/2021

-help
    Display this message.

-list [-virtual]
    Return list of available printer (excepted: OneNote for Windows 10, OneNote (Desktop), Microsoft XPS Document Writer, Microsoft Print to PDF, Fax)

-file filepath [-printer printer_name] [-virtual]
    Print specified file on default system printer. Use -printer to specify printer to use. Printer name must be available un -list response.

-batch filepath [-printer printer_name] [-virtual]
    Print each document specified un batch file on default system printer. Batch file must be a .txt. Each file to print must be write on its own line.
    Use -printer to specify printer to use. Printer name must be available un -list response.

-virtual
    Use this option after all other arguments to enable printing on virtual printer 'Microsoft Print to PDF'

To print one file to printer HP1FF6CC (HP OfficeJet Pro 6970)

python main.py -file "D:mysystempathtofilepattern.ps" -printer "HP1FF6CC (HP OfficeJet Pro 6970)"

To print one file to virtual printer Microsoft Print to PDF (generally for text purpose, paper is quickly expensive)

python main.py -file "D:mysystempathtofilepattern.ps" -printer "Microsoft Print to PDF" -virtual

Answered By: Arthur

If you have Adobe try this:

import win32api
import winreg
import subprocess
import time

def get_adobe_executable():
    with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as conn:
        with winreg.OpenKey(conn, r'SOFTWAREMicrosoftWindowsCurrentVersionApp PathsAcroRd32.exe', 0, winreg.KEY_READ) as hkey:
            value = winreg.QueryValue(hkey, None)
            if value:
                value = '"{}"'.format(value)
                return value.strip()
    return None

def print_pdf_file(file, printer_name=None, secs=5):
    cmd = get_adobe_executable()
    if cmd is None:
        return False
    if printer_name:
        cmd = '{} /h /t "{}" "{}"'.format(cmd, file, printer_name)
    else:
        cmd = '{} /p /h "{}"'.format(cmd, file)
    proc = subprocess.Popen(cmd)
    time.sleep(secs)
    proc.kill()
    
    return True

if __name__ == "__main__":
    print_pdf_file("doc.pdf") # print with default printer
    print_pdf_file("doc.pdf", "HP LaserJet Pro M102") # setting the printer name

get_adobe_executable

Get the Adobe from the registry(you can also get the print command like the one that you right click the pdf file and select Print from the menu but I wanted to just get the path then configure it according to the printer configuration)

print_pdf_file

If you don’t set the printer_name variable, Adobe will print with the default printer

After executing the print command it will wait 5 seconds and then close Adobe program, Adobe it does not have command line option (as today of writing) to exit after printing the file, here you can see the command line options

Answered By: tttony

There is another method to send the file to printer without adobe reader also, by SumatraPDF

install SumatraPDF application and add the SumatraPDF.exe location to the path

# import subprocess and os
import subprocess
import os

# file path
file_name = "Document.pdf"
if file_name:
    print("exist")

# send data to the printer

try:
    subprocess.call(['SumatraPDF.exe', '-print-to', "Barcode",
                     '-print-settings', "1x", file_name])

except BaseException as msg:
    print(msg)

there is no need to have any adobe reader, and for every time it wont open the adobe reader to read data,
but issue is that should try on page orientation and page size,
but if those are same always for pdf seems we can change in the printer properties directly,

only to add exe path to the file path in systementer image description here

thats it

Answered By: chanti
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.