PyPDF2无损切割PDF页面(将A3尺寸的PDF一分为二的更优方案)

上一篇文章(//www.greatytc.com/p/c35ed87ebb30)说到,利用pymupdf和pillow模块将A3尺寸的PDF转换为两张A4大小的页面,基本满足了使用要求。但是,效果仍然不够理想。因为pdf转化成图片的过程中必然存在数据的压缩,这将导致文件的清晰度降低。放大4倍后的对比如下,转换后的图片放大后明显模糊:

原始效果

转为图片后再打印成pdf

最理想的方法是像“A-PDF Page Cut”软件那样直接在原文件上裁剪。我一直认为:“对于大多数人来说,只要是你能想到的,那么世界上大概率早有实现了。”本着精益求精的态度,继续挖掘python的潜力,皇天不负有心人,终于又找到了一个PyPDF2模块。与pymupdf模块相比,PyPDF2的功能很简单,本身只实现了四个类,但是却能够直接对pdf文件进行裁剪,可谓小而精。需要注意的一点是,这个模块的坐标系和Javascript不一样,它是以左下角作为原点,而JS的原点在左上角。
具体实现代码如下:

# -*- coding: UTF-8 -*-  
from PyPDF2 import PdfFileReader, PdfFileWriter
import os
from pathlib import Path

def split_pdf(infile, out_path):
    if not os.path.exists(out_path):
        os.makedirs(out_path)
    with open(infile, 'rb') as infile:
    
        pdfReader = PdfFileReader(infile)
        number_of_pages = pdfReader.getNumPages()  
        
        for i in range(number_of_pages):

            page = pdfReader.getPage(i)
            width = float(page.mediaBox.getWidth())
            height = float(page.mediaBox.getHeight())
        
            pdfReader=PdfFileReader(infile)  
            pdfWriter = PdfFileWriter()    
            page_top = pdfReader.getPage(i)
            page_top.mediaBox.lowerLeft = (0,0)
            page_top.mediaBox.lowerRight = (width/2,0)
            page_top.mediaBox.upperLeft = (0,height)
            page_top.mediaBox.upperRight = (width/2,height)
            pdfWriter.addPage(page_top)
            out_file_name = out_path + Path(str(infile)).stem+str(i+1)+'_left.pdf'
            with open(out_file_name, 'wb') as outfile:
                pdfWriter.write(outfile) 
            
            #bottom page
            pdfReader=PdfFileReader(infile)  
            pdfWriter = PdfFileWriter()    
            page_buttom = pdfReader.getPage(i)
            page_buttom.mediaBox.lowerLeft = (width/2,0)
            page_buttom.mediaBox.lowerRight = (width,0)
            page_buttom.mediaBox.upperLeft = (width/2,height)
            page_buttom.mediaBox.upperRight = (width,height)
    
            pdfWriter.addPage(page_buttom)   
            out_file_name = out_path + Path(str(infile)).stem + str(i+1)+'_right.pdf' 
            with open(out_file_name, 'wb') as outfile:
                pdfWriter.write(outfile) 

if __name__ == '__main__':
    p=Path.cwd()
    filelist = list(p.glob('*.pdf'))
    for i in filelist:
        in_File = Path(str(i))
        out_Path = './Single/' 
        split_pdf(in_File, out_Path)

新方法放大4倍后的效果如图:


更好的效果

新方法的文字清晰度与原图完全一致。至此,可以说完美解决了问题。
其实上一版的解决方案也不是毫无用处,如果碰到不想让别人复制文件里的文字,希望至少给提取增加点难度的情况时,可以将pdf页面转成图片,然后再打印成pdf。那样对方要提取内容就只能靠OCR了,文件的保密性还是能够提高一点点的。

下一步计划仔细研究一下这个模块的源代码,看看能不能移植到C++语言里编译成exe程序,python源码打包后巨大的体积实在不利于传播。

补充

  1. 闲下来的时候又仔细看了一下pymupdf模块的文档,细看之下,不禁虎躯一震,看文档不仔细,颇觉惭愧。文件无损转换方案赫然在目!源码如下:
"""
Create a PDF copy with split-up pages (posterize)
---------------------------------------------------
License: GNU AFFERO GPL V3
(c) 2018 Jorj X. McKie

Usage
------
python posterize.py input.pdf

Result
-------
A file "poster-input.pdf" with 4 output pages for every input page.

Notes
-----
(1) Output file is chosen to have page dimensions of 1/4 of input.

(2) Easily adapt the example to make n pages per input, or decide per each
    input page or whatever.

Dependencies
------------
PyMuPDF 1.12.2 or later
"""
import fitz, sys
infile = sys.argv[1]  # input file name
src = fitz.open(infile)
doc = fitz.open()  # empty output PDF

for spage in src:  # for each page in input
    r = spage.rect  # input page rectangle
    d = fitz.Rect(spage.cropbox_position,  # CropBox displacement if not
                  spage.cropbox_position)  # starting at (0, 0)
    #--------------------------------------------------------------------------
    # example: cut input page into 2 x 2 parts
    #--------------------------------------------------------------------------
    r1 = r / 2  # top left rect
    r2 = r1 + (r1.width, 0, r1.width, 0)  # top right rect
    r3 = r1 + (0, r1.height, 0, r1.height)  # bottom left rect
    r4 = fitz.Rect(r1.br, r.br)  # bottom right rect
    rect_list = [r1, r2, r3, r4]  # put them in a list

    for rx in rect_list:  # run thru rect list
        rx += d  # add the CropBox displacement
        page = doc.new_page(-1,  # new output page with rx dimensions
                           width = rx.width,
                           height = rx.height)
        page.show_pdf_page(
                page.rect,  # fill all new page with the image
                src,  # input document
                spage.number,  # input page number
                clip = rx,  # which part to use of input page
            )

# that's it, save output file
doc.save("poster-" + src.name,
         garbage=3,  # eliminate duplicate objects
         deflate=True,  # compress stuff where possible
)

2. 还有一个比较简单的方案

这个方法比较适合没有编程经验的小白,下载安装mupdf软件(免费的),在命令行输入如下命令:

mutool poster [-x |-y] [number] input.pdf output.pdf

可以快速分割当前文件,其中各参数含义是:

  • -x:沿水平方向平均分割
  • -y: 沿垂直方向平均分割
  • number:分割块数
  • input.pdf:原文件名
  • output.pdf:分割后的文件名
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容