在实际打印文档之前预览PDF文件并选择打印机
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在实际打印文档之前预览PDF文件并选择打印机相关的知识,希望对你有一定的参考价值。
我目前正在使用Python3 / tkinter开发一个主要在Mac上运行的应用程序,需要打印PDF文件。
在过去,我已经设法通过使用bash脚本中的一些命令自动将PDF文件发送到打印机,所以我想我最终可能会使用这种方法作为最后的手段。
但是,我从未找到指定一台打印机的方法,它总是将其直接发送到当前选定的打印机(通常是最后使用的打印机)。问题是所有这些计算机都连接到多台打印机,而某些打印机不适合A4文档(例如,标签打印机)。
有没有人知道是否有任何方法从命令行启动预览应用程序,或任何允许我们在实际打印之前预览和选择打印机的外部模块?
答案
这是我刚刚创建的一个程序,允许您选择打印机并进行打印。
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("
")
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)上。
我只测试了.py
文件。不幸的是,印刷文件的格式并不是真正理想的(因为我不是真正的专家,如何使用lpr
打印文件),但你可以检查lpr
的选项,看看你能用它做什么。
此外,我没有创建所选文件的任何预览,但您可以使用PIL(至少对于图像)实现此目的...
注意:注意,不要在print
按钮上单击100次,否则队列中将有100个文件要打印!你可能想以某种方式解决这个问题。
以上是关于在实际打印文档之前预览PDF文件并选择打印机的主要内容,如果未能解决你的问题,请参考以下文章