PDF(Portable Document Format)是工作上常會用到的一種文件格式,有較不容易修改、傳輸方便、設備相容性和印刷品質較佳等優點。一般我們開發的軟體要自動發報告、帳單或收據給客戶,也都會優先選擇PDF為主要格式。

合併PDF是目前加入浮水印的一種簡便方法,當浮水印樣式和內容固定的情況下開發會較為單純。本文以Pyhton的PyPDF4套件為例,雖然PyPDF4和PyPDF2不完全兼容,但此範例中所導入的函示方法和PyPDF2一樣,將套件名稱改掉後程式碼可以互相通用。

用來示範的兩份PDF檔案,original_doc.pdfwatermark.pdf,程式會將浮水印合併到 original_doc.pdf 每一頁。

original_doc.pdfwatermark.pdf
original_docwatermark

套件安裝

首先,安裝最新版的PyPDF4 (以下指令基於python3):

pip3 install PyPDF4

合併浮水印

merge_watermark()是實現合併浮水印的方法,每當合併完一頁PDF浮水印就透過writer實例立刻輸出。

from PyPDF4 import PdfFileWriter, PdfFileReader

def merge_watermark(input_pdf, output_pdf, watermark):
    """
    Merge watermark to target PDF
    """
    watermark_obj  = PdfFileReader(watermark)
    watermark_page = watermark_obj.getPage(0)
    pdf_reader = PdfFileReader(input_pdf)
    pdf_writer = PdfFileWriter()

    # Add watermark to each page 
    for page_num in range(pdf_reader.getNumPages()):
        page = pdf_reader.getPage(page_num)
        page.mergePage(watermark_page)
        pdf_writer.addPage(page)

        with open(output_pdf, 'wb') as f:
            pdf_writer.write(f)

ArgumentParser

程式就是要能夠帶參數才可以方便使用。使用ArgumentParser解析並傳遞參數給Python程式碼。

-i--input參數指定要被加入浮水印的PDF檔案路徑
-o--output參數指定檔案輸出路徑,指定的路徑資料夾不存在就創建新的;但如果不指定輸出路徑,預設就會將檔案命名<原PDF檔名>-watermarked.pdf並輸出至原始PDF所在的資料夾。
-w--watermark參數指定浮水印PDF檔案路徑
def parse_arguments():
    """ 
    Parse command line arguments
    """
    parser = ArgumentParser(description="Add watermarks to PDF in path")
    parser.add_argument("-i", "--input",     help="Path to input PDF", required=True, type=str)
    parser.add_argument("-o", "--output",    help="Path to output PDF")
    parser.add_argument("-w", "--watermark", help="Path to watermark PDF", required=True, type=str)
    return parser.parse_args()

def main():
    args = parse_arguments()
    source_pdf   = os.path.abspath(args.input)
    source_dir   = os.path.dirname(source_pdf)
    fname, f_ext = os.path.splitext(os.path.basename(source_pdf))
    
    if args.output is None:
        ofname = os.path.join(source_dir, '{}{}{}'.format(fname, "-watermarked", f_ext))
    else:
        ofname     = os.path.abspath(args.output)
        output_dir = os.path.dirname(ofname)
        
        try:
            if not os.path.exists(output_dir):
                os.makedirs(output_dir)
        except EnvironmentError:
            sys.exit("Unable to create folder: " + output_dir)

    if os.path.isfile(source_pdf):
        merge_watermark(
            input_pdf  = source_pdf,  
            output_pdf = ofname, 
            watermark  = args.watermark
        )
    else:
        sys.exit("\nPDF file {} not exists!\n".format(source_pdf))

if __name__ == '__main__':
    import os
    import sys
    from argparse import ArgumentParser
    main()


將程式儲存命名為 watermark.py 就可以來執行看看。

python3 watermark.py -i original_doc.pdf -w watermark.pdf

輸出結果請見下圖。

original_doc-watermarked.pdf
watermarked

以本人實際開發經驗來說,如果浮水印本來就屬於PDF該有的內容,應該在一開始撰寫模板的時候就考慮進去,到後面使用合併的方式其實都算是最後手段了。

Reference