11from PyPDF2 import PdfFileMerger
2+ import argparse
3+ import sys
4+
5+ try :
6+ from PyPDF2 import PdfMerger # new name
7+ except ImportError :
8+ from PyPDF2 import PdfFileMerger as PdfMerger # fallback for older versions
29
310
411def by_appending ():
@@ -8,14 +15,89 @@ def by_appending():
815 merger .append ("testPDF12.pdf" )
916
1017 merger .write ("mergedPDF.pdf" )
18+ f1 .close
1119
1220def by_inserting ():
1321 merger = PdfFileMerger ()
1422 merger .append ("testPDF1.pdf" )
1523 merger .merge (0 , "testPDF2.pdf" )
1624 merger .write ("mergedPDF.pdf" )
1725
26+ def merge_pdfs (pdfs : list [Path ], output : Path ) -> None :
27+ """Append all given PDFs in order and write to output."""
28+ merger = PdfMerger ()
29+ files = []
30+ try :
31+ for pdf in pdfs :
32+ fh = pdf .open ("rb" )
33+ files .append (fh )
34+ merger .append (fh )
35+ merger .write (str (output ))
36+ print (f"[ok] Merged { len (pdfs )} PDFs into { output } " )
37+ finally :
38+ for fh in files :
39+ fh .close ()
40+
41+
42+ def insert_pdf (pdfs : list [Path ], insert : Path , index : int , output : Path ) -> None :
43+ """Append PDFs and insert another at given index."""
44+ merger = PdfMerger ()
45+ files = []
46+ try :
47+ for pdf in pdfs :
48+ fh = pdf .open ("rb" )
49+ files .append (fh )
50+ merger .append (fh )
51+
52+ with insert .open ("rb" ) as ins_fh :
53+ merger .merge (index , ins_fh )
54+
55+ merger .write (str (output ))
56+ print (f"[ok] Inserted { insert } at index { index } -> { output } " )
57+ finally :
58+ for fh in files :
59+ fh .close ()
60+
61+
62+ def parse_args (argv ):
63+ parser = argparse .ArgumentParser (description = "Merge multiple PDFs" )
64+ parser .add_argument ("pdfs" , nargs = "+" , help = "Input PDF files" )
65+ parser .add_argument ("-o" , "--output" , default = "mergedPDF.pdf" , help = "Output file name" )
66+ parser .add_argument ("--insert" , help = "Optional PDF to insert" )
67+ parser .add_argument ("--at" , type = int , default = 0 , help = "Index to insert at (default=0)" )
68+ return parser .parse_args (argv )
69+
70+
71+ def validate (paths : list [str ]) -> list [Path ]:
72+ pdfs = []
73+ for p in paths :
74+ path = Path (p )
75+ if not path .exists ():
76+ sys .exit (f"[error] File not found: { path } " )
77+ if path .suffix .lower () != ".pdf" :
78+ sys .exit (f"[error] Not a PDF: { path } " )
79+ pdfs .append (path )
80+ return pdfs
81+
82+
83+ def main (argv = None ):
84+ args = parse_args (argv or sys .argv [1 :])
85+ pdfs = validate (args .pdfs )
86+ out = Path (args .output )
87+
88+ if args .insert :
89+ insert = validate ([args .insert ])[0 ]
90+ insert_pdf (pdfs , insert , args .at , out )
91+ else :
92+ if len (pdfs ) < 2 :
93+ sys .exit ("[error] Need at least 2 PDFs to merge" )
94+ merge_pdfs (pdfs , out )
95+
96+
1897
1998if __name__ == "__main__" :
99+
20100 by_appending ()
21101 by_inserting ()
102+
103+ main ()
0 commit comments