【问题标题】:Python silent print PDF to specific printerPython静默打印PDF到特定打印机
【发布时间】:2015-01-27 12:32:17
【问题描述】:

我有一个 PDF 文档,我想用我的 python 应用程序打印它。

我已经尝试了here (Print PDF document with python's win32print module?) 中的解决方案,但是当我安装实际版本的 Ghostscript 9.15 时,它没有 gsprint.exe

我使用该命令的方式是使用命令os.startfile('PDFfile.pdf', "print"),但它会打开默认查看器(我的是Adobe Reader),打印后它仍然打开,尝试使用os.system("TASKKILL /F /IM AcroRD32.exe") 终止进程会杀死其他打开的窗口,我不想要。

使用下一个命令,它也打印,但它让 Adob​​e Reader 也打开了

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

我也见过this answer,但他们建议再次使用gsprint.exe

有人有gsprint.exe 文件或任何其他解决方案吗?

注意:当我使用另一个默认程序打开 PDF 文件(如 Chrome 或 Windows Reader)时,我总是在执行上面的命令时遇到异常,'(31, 'ShellExecute', 'A device attached to the system is not functioning.')'[Error 1155] No application is associated with the specified file for this operation: 'PDFfile.pdf' 带有 @ 987654331@命令

【问题讨论】:

    标签: python pdf printing


    【解决方案1】:

    经过数小时搜索正确文件后,我终于找到了问题的答案。

    您可以在HERE下载GSPRINT

    你可以在HERE下载Ghostscript GPL

    在您的 PC (Windows) 中使用此提取的文件,您可以使用此命令打印您的 PDF

    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)
    

    GhostScript也可以在官方页面HERE找到

    我找到了 64 位的 gsprint.exe HERE

    我希望这会有所帮助。

    【讨论】:

    • 64 位链接的 gsprint.exe 已失效(2017 年 10 月),但这个适用于 32 位:pages.cs.wisc.edu/~ghost/gsview/gsprint.htm
    • 对于 Windows,它是旧链接。和 ubuntu 或 linux 这个包不存在,这是窗口特定的答案
    • 这不会静默打印文件 - 它会打开一个窗口大约一秒钟然后再次关闭!
    • gsprint 链接失效,我找不到它:(
    【解决方案2】:

    我知道这是一个老问题,但如果有人在这里寻找它,我就是这样解决的。

    我在 windows 10 64 位和 python3-ghostscript 库上使用 python 3.8 和 gs9.52,您可以使用 pip install python3-ghostscript 安装我还使用 pypiwin32 来获取默认打印机名称,您可以使用 pip @ 安装它987654322@

    这是工作脚本

    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)
    

    这里有几件事需要注意,我使用 '#' 而不是 '=',因为由于某种原因它不能使用 '='。

    如果这对您不起作用,请尝试将 -sDEVICE 开关更改为您的打印机类型,例如当我使用 HP LaserJet 时,它会提示我,所以我将 -sDEVICE 更改为laserjet 并且它有效,您可以通过在终端中运行gs -h 来获取设备列表

    【讨论】:

    • 如果您已经有要打印的 pdf 文件...您可以将行 f'"{temp1}"' 替换为 f'"{f}"' 其中f = os.path.join(os.getcwd(), 'testprint.pdf').replace('\\', '\\\\')。当然一定要在顶部import os。如果您满足所有这些要求,您将不需要args = [...] 以上的任何内容,直到import ghostscript 行,因为import render_to_pdf 没有在任何地方定义,您也不需要import win32print。感谢您提供这么棒的代码!
    • 另外,, "-dFIXEDMEDIA", "-dPSFitPage", 作为附加参数将有助于将内容集中在页面上!
    【解决方案3】:

    这是一种在没有gsprintwin32api 的情况下在与python 脚本相同的目录中静默打印pdf 的方法。它允许更多的 GhostScript 自定义,例如选择宽度/高度等。

    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)
    

    如果您使用的是 32 位版本的 GhostScript,那么您将使用 gswin32c

    【讨论】:

    • 这不会静默打印文件 - 它会打开一个窗口大约一秒钟然后再次关闭!
    • @bdoubleu gswin64cgswin64 有什么区别?谢谢
    【解决方案4】:

    下面的代码会阻塞当前任务

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

    打印帮助后杀死读者不会阻塞当前任务

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

    但它也会关闭其他 pdf 文件。

    如果不能使用 gsprint,请使用 acrobat 命令

    import win32print
    import subprocess
    import time
    pdf_file  = 'D:\d1\d1.pdf'
    acrobat = 'C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.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)
    

    它不会阻塞当前任务并关闭其他pdf文件。

    【讨论】:

    • 这很适合我的需要,但是,即使在关闭窗口后,我的 adobe acrobat 仍然保持打开状态。有没有办法确保它也关闭?
    • 试试下面的,cmd = '"{}" /n /o /t "{}" "{}"'.format(acrobat, file_path, printer_name) proc = subprocess.Popen(cmd , stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 标准输出, stderr = proc.communicate() proc.terminate()
    • 我似乎仍然无法完成这项工作。它使用 pdf 关闭文件,但 adobe acrobat 本身保持打开状态。
    • 尝试最小化它,我想我不会再来了,对我来说Adobe进入任务栏并且不会进入打开状态
    • 我相信,adobe 在任务栏中一直处于打开状态,我们无法更改它。
    【解决方案5】:

    如果要打印特定页面和其他一些参数,应该在gsprint的参数中指定如下:

    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)
    

    【讨论】:

      【解决方案6】:

      所以这并不是完全静默的,但它会自动关闭对话框并打印,还对硒有一种奇怪的依赖,这是你本身不会想到的,但这实际上对我有用,因为我在我不能下载 ghostscript,也不能下载 adobe 的 pdf 阅读器。我认为它可能会帮助其他人,某个地方,某个地方,某个时间......

      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)
          
      
          
      

      【讨论】:

        【解决方案7】:

        根据之前的答案和其他帖子,我开发了以下脚本来从 Laravel 网站打印 .pdf.ps

        我使用了python 3.9Ghostscript 9.54(对于 64 位)。 pywin32python3-ghostscript 库也是必需的。

        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:])
        

        以下命令解释如何使用它: 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'
        

        将一个文件打印到打印机HP1FF6CC (HP OfficeJet Pro 6970)

        python main.py -file "D:\my\system\path\to\file\pattern.ps" -printer "HP1FF6CC (HP OfficeJet Pro 6970)"

        将一个文件打印到虚拟打印机Microsoft Print to PDF(通常用于文本目的,纸张很快就会很贵)

        python main.py -file "D:\my\system\path\to\file\pattern.ps" -printer "Microsoft Print to PDF" -virtual

        【讨论】:

          【解决方案8】:

          如果你有 Adob​​e,试试这个:

          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'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.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

          从注册表中获取 Adob​​e(您也可以像右键单击 pdf 文件并从菜单中选择“打印”一样获取打印命令,但我只想获取路径然后根据打印机配置进行配置)

          print_pdf_file

          如果您不设置 printer_name 变量,Adobe 将使用默认打印机进行打印

          执行打印命令后等待 5 秒然后关闭 Adob​​e 程序,Adobe 没有命令行选项(截至发稿日)打印文件后退出,here 可以看到命令行选项

          【讨论】:

            猜你喜欢
            • 2012-12-17
            • 2017-05-24
            • 1970-01-01
            • 2015-06-07
            • 2011-05-28
            • 1970-01-01
            • 2016-06-02
            • 2013-11-08
            相关资源
            最近更新 更多