Pdf

混合支持列印?

  • September 9, 2019

我需要生成並列印一個文件,其中大多數頁面列印在 A4 標籤上(來自列印機的旁路紙盤),一些分隔頁列印在普通 A3 紙上(來自另一個托盤)。

目前,我正在使用 Python 和 Reportlab,並且我知道如何生成具有混合頁面大小的文件(A4 用於首頁,A3 用於分隔頁)。但是當我用 evince 列印它時,我必須選擇一個頁面尺寸進行列印,並且所有頁面都在相同的頁面尺寸和同一個托盤上列印……

有沒有一種方法可以讓我的文件在不同紙盤的不同紙張尺寸的首頁面和分隔頁面上列印?

感謝 meuh 的幫助,我可以編寫一個簡短的 Python 程序,將我使用現有程序生成的 PDF 轉換為 PostScript 文件,並使用特定於設備的setpagedevice命令。

該程序非常適合我的使用,但我認為它可能對其他人有用,作為起點。這裡是:

#! /usr/bin/env python3

import argparse
import re
import subprocess
import sys

import PyPDF2

def make_postscript(f):
   """Convert a PDF file to PostScript, with pdf2ps, and yield it line by line."""
   with subprocess.Popen(['pdf2ps', '/dev/stdin', '/dev/stdout'], stdin=f, stdout=subprocess.PIPE, stderr=None) as proc:
       for line in proc.stdout:
           yield line

def add_device_control(postscript, separator_pages):
   """Add device control commands to a PostScript file with DSC comments."""
   DSC_page_re = re.compile(b'%%Page: (?P<page_name>.+) (?P<page_number>[1-9][0-9]*)$')
   DSC_begin_page_setup_re = re.compile(b'%%BeginPageSetup$')
   page_number = None
   for line in postscript:
       m = DSC_page_re.match(line)
       if m:
           assert page_number is None
           page_number = int(m.group('page_number').decode('ASCII'))-1
           yield line
           continue
       m = DSC_begin_page_setup_re.match(line)
       if m:
           assert page_number is not None
           yield line
           if page_number in separator_pages:
               yield b'mark { << /PageSize [1191 842] /ImagingBBox null /MediaType (Plain) /MediaPosition null >> setpagedevice } stopped cleartomark\n'
           elif page_number not in separator_pages:
               yield b'mark { << /PageSize [595 842] /ImagingBBox null /MediaType (Labels) /MediaPosition 0 >> setpagedevice } stopped cleartomark\n'
           page_number = None
           continue
       yield line
   assert page_number is None

def walk_outline(outline, depth=0):
   """Walk through the outline of a PDF file in a depth-first search way, and yield each element with its zero-based depth."""
   for obj in outline:
       if isinstance(obj, PyPDF2.pdf.Destination):
           yield depth, obj
       elif isinstance(obj, list):
           for result in walk_outline(obj, depth+1):
               yield result
       else:
           assert False

def find_separator_pages(f):
   """Find the page number of the separator pages in a PDF file"""
   separator_pages = set()
   reader = PyPDF2.PdfFileReader(f)
   for depth, obj in walk_outline(reader.outlines):
       page_num = reader._getPageNumberByIndirect(obj.page)
       if depth == 0:
           assert page_num >= 0
           separator_pages.add(page_num)
   return separator_pages

def main():
   parser = argparse.ArgumentParser()
   parser.add_argument("input_file", metavar="input.pdf", type=argparse.FileType('rb'))
   parser.add_argument("output_file", metavar="output.ps", nargs="?", type=argparse.FileType('wb'), default=sys.stdout.buffer)
   args = parser.parse_args()

   separator_pages = find_separator_pages(args.input_file)
   args.input_file.seek(0)
   postscript = make_postscript(args.input_file)
   postscript = add_device_control(postscript, separator_pages)
   for line in postscript:
       args.output_file.write(line)

if __name__ == "__main__":
   main()

再次感謝 meuh 在評論中的幫助。

引用自:https://unix.stackexchange.com/questions/538938