预览PDF文件并在实际打印文档之前选择打印机 [英] Preview a PDF file and choose printer before actually printing the document

查看:90
本文介绍了预览PDF文件并在实际打印文档之前选择打印机的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用Python3/tkinter开发一个应用程序,该应用程序将主要在Mac上运行,并且需要打印PDF文件.

I am currently developing an application in Python3/tkinter that will run primarily on Macs and will need to print PDF files.

过去,我已经设法通过在bash脚本中使用一些命令来自动将PDF文件发送到打印机,所以我认为我最终可能会使用该方法.

In the past, I have managed to send PDF files to printer automatically by using some commands in a bash script, so I think I could end up using that approach as a last resort.

但是,我从未找到一种指定打印机的方法,它总是将其直接发送到当前选择的打印机(通常是最后使用的打印机)中.问题在于所有这些计算机都连接到多于一台打印机,并且某些打印机不适合A4文档(例如,标签打印机).

However, I never found a way to specify one printer, it would always send it right into the currently selected printer (usually the last used one). The problem is that all those computers are connected to more that one printer, and some of the printers are not suitable for A4 documents (for instance, label printers).

有人知道是否有任何方法可以从命令行启动预览应用程序,或者有任何外部模块可以让我们在实际打印之前预览并选择打印机?

Does anyone know if there is any way to launch the Preview application from command line, or any external module that allows us to preview and choose printers before actually printing?

推荐答案

这是我刚刚创建的程序,允许您选择打印机并进行打印.

Here's a program I've just created that allows you to select a printer and print.

import tkinter as tk
from tkinter.filedialog import askopenfilename
import subprocess
from pprint import pprint
import platform
import sys

def which(program):
    # http://stackoverflow.com/a/377028/3924118
    import os
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            path = path.strip('"')
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None


class FilePrinterDialog(tk.Toplevel):

    def __init__(self, root, *args, **kwargs):
        tk.Toplevel.__init__(self, root, *args, **kwargs)
        self.root = root

        self.body = tk.Frame(self, bg="lightblue")
        self.body.pack(expand=True, fill="both")

        self.title_frame = tk.Frame(self.body, pady=5)
        self.title_frame.pack(fill="both", pady=(15, 5))

        self.title = tk.Label(self.title_frame,  text="Let's print!")
        self.title.pack(fill="x")

        # Current selected printer of your system
        self.system_default_destination = self._find_system_default_destination()

        # Finds printer names
        self.printers_names = self._find_printers_names()

        self.selected_file = None  # To hold the selected file's name
        self.data_bytes = None  # Bytes read from the selected file to print
        self.selected_printer = None  # Hols name of selected printer

        # Display them
        self.printers_frame = tk.Frame(self.body, bg="lightblue", padx=10, pady=10)
        self.printers_frame.pack(expand=True, fill="both")
        self._display_printers()

        self.bottom_frame = tk.Frame(self.body, pady=5)
        self.bottom_frame.pack(fill="both", pady=(5, 16))
        self.open_file_chooser = tk.Button(self.bottom_frame,
                                           text="Open file chooser",
                                           command=self._select_file)
        self.open_file_chooser.pack(side="left", padx=10)

        self.print_file = tk.Button(self.bottom_frame,
                                           text="Print",
                                           command=self._print_selected_file)
        self.print_file.pack(side="right", padx=10)


        self._make_modal()

    def _read_file(self):
        # NOT USED!
        if not self.selected_file:
            raise ValueError("No file chosen")
        with open(self.selected_file, "rb") as in_file: # opening for [r]eading as [b]inary
            return in_file.read() # if you only wanted to read 512 bytes, do .read(512)

    def _print_selected_file(self):
        if not self.selected_file:
            print("No file selected yet!")
        else:
            subprocess.call(["lpr", self.selected_file])

    def _select_file(self):
        self.selected_file = askopenfilename(title = "Choose file to print")
        print(self.selected_file)

    def _on_listbox_selection(self, event):
        self.selected_printer = self._find_current_selected_printer()

        # Sets the printer on your system
        subprocess.call(["lpoptions", "-d", self.selected_printer])
        print("Selected printer:", self.selected_printer)

    def _find_current_selected_printer(self):
        curselection = self.listbox.curselection()
        if len(curselection) > 0:
            return self.listbox.get(curselection[0])   
        else:
            return None

    def _display_printers(self):
        self.scrollbar = tk.Scrollbar(self.printers_frame)
        self.scrollbar.pack(side="right", fill="y")

        self.listbox = tk.Listbox(self.printers_frame,
                                  yscrollcommand=self.scrollbar.set,
                                  selectbackground="yellow",
                                  selectmode="single",
                                  height=6)

        for printer_name in self.printers_names:
            self.listbox.insert("end", printer_name)

        # Keep track of selected listbox
        self.listbox.bind("<<ListboxSelect>>", self._on_listbox_selection)

        # Sets first listbox as selected
        self.listbox.select_set(0) # Sets focus
        self.listbox.event_generate("<<ListboxSelect>>")

        self.listbox.pack(side="left", fill="both", expand=True)
        self.scrollbar.config(command=self.listbox.yview)

    def _find_system_default_destination(self):
        return subprocess.getoutput("lpstat -d").split(": ")[1]

    def _find_printers_names(self):
        # Command to obtain printer names based on: https://superuser.com/a/1016825/317323
        return subprocess.getoutput("lpstat -a | awk '{print $1}'").split("\n")

    def _make_modal(self):
        # Makes the window modal
        self.transient(self.root)
        self.grab_set()
        self.wait_window(self)


if __name__ == "__main__":
    if not which("lpoptions") or not which("lpr") or not which("awk") or not which("lpstat"):        
        sys.stderr.write("Requirements: lopotions, lpr, lpstat and awk not satisfied")
    else:
        root = tk.Tk()
        opener = tk.Button(root, text="Open printer chooser", command=lambda: FilePrinterDialog(root))
        opener.pack()
        root.mainloop()

仅当您具有我在程序中指定的必需依赖项时,此程序才有效.你应该有这些,因为我也在 Mac OS X (Sierra) 上.

This program only works if you have the required dependencies which I specify in the program. You should have those since I'm also on a Mac OS X (Sierra).

我仅使用 .py 文件进行了测试.不幸的是,打印文档的格式并不是真正想要的(因为我不是真正的如何使用 lpr 来打印文件的专家),但是您可以检查的选项lpr ,看看你能用它做什么.

I've tested only with a .py file. Unfortunately, the format of the printed documented isn't really as desired (since I'm not really an expert on how to use lpr to print files), but you can check the options of lpr and see what you can do with it.

此外,我还没有为所选文件创建任何预览,但是您可以使用PIL(至少对于图像而言)来实现此目的...

Also, I've not created any preview of the selected file, but you may achieve this using PIL (at least for images)...

注意:请小心,不要在 print 按钮上单击100次,否则队列中将要打印100个文件!您可能想以某种方式解决此问题.

Note: be careful, do not click 100 times on the print button, otherwise you will have 100 files in the queue to be printed! You may want to fix this somehow.

这篇关于预览PDF文件并在实际打印文档之前选择打印机的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆