今回の内容
PyPDF2を使って、見開きでスキャンした資料などのpdfファイルを左右に2分割するスクリプトのメモです。
座標参照の改善(追記:2021-12-21)
表示領域を変更しているだけで本体はそのままのようです。ファイルサイズも変わらないためあまり問題はないように思いますが、例えばこのスクリプトを二度がけすると本体の座標を参照するため想定通りの挙動にはなりません。
なので、切り取り領域の座標を参照し、原点が変動することを考慮して計算するよう以下のように修正しました。
ついでに、縦長か横長かを判定して長辺を2分割する機能もつけております。
from PyPDF2 import PdfFileWriter, PdfFileReader
import copy
def split_pdf(input_pdf, output_filename):
pdf_file = PdfFileReader(open(input_pdf, 'rb'))
marged = PdfFileWriter()
page_num = pdf_file.getNumPages()
for i in range(0, page_num):
page_L = pdf_file.getPage(i)
page_R = copy.copy(page_L)
lx,ly,ux,uy = page_L.cropBox
(w,h) = (ux-lx),(uy-ly)
if w > h:
page_L.cropBox.lowerRight = (lx+w/2, ly)
page_R.cropBox.lowerLeft = (lx+w/2, ly)
else:
page_L.cropBox.lowerLeft = (lx, ly+h/2)
page_R.cropBox.upperLeft = (lx, ly+h/2)
marged.addPage(page_L)
marged.addPage(page_R)
outputStream = open(output_filename, "wb")
marged.write(outputStream)
outputStream.close()
ソースコード
from PyPDF2 import PdfFileWriter, PdfFileReader
import copy
def split_pdf(input_pdf, output_filename):
pdf_file = PdfFileReader(open(input_pdf, 'rb'))
marged = PdfFileWriter()
page_num = pdf_file.getNumPages()
for i in range(0, page_num):
page_L = pdf_file.getPage(i)
page_R = copy.copy(page_L)
(w, h) = page_L.mediaBox.upperRight
page_L.mediaBox.upperRight = (w/2, h)
marged.addPage(page_L)
page_R.mediaBox.upperLeft = (w/2, h)
marged.addPage(page_R)
outputStream = open(output_filename, "wb")
marged.write(outputStream)
outputStream.close()
def sample():
input_pdf = "input.pdf"
output_filename = "output.pdf"
split_pdf(input_pdf, output_filename)
if __name__ == "__main__":
sample()
使い方
split_pdf()に対して、分割するpdfファイルと、出力する際のファイル名を与えることでpdfファイルを2分割します。
簡単な解説
一つのページを左ページ用と右ページ用に2つ用意します。(page_L, page_R)
ページは左下を始点とするので、右上の座標から横幅と高さを取得します。(w, h)
左ページには右側の、右ページには左側の座標を指定することで、それを基準にそれぞれ切り取ります。
今回は、左ページには右上の座標を (w/2, h)、右ページには左上の座標を (w/2, h)として指定し、左右に2分割しています。
蛇足、右ページについてはpage_R.mediaBox.lowerLeft = (w/2, 0)
とした方が分かりやすいのかもしれません。
使い方の例
自分は以下のように使っています。追加、変更分のみ書きます。
import sys, os
def main():
argv = [sys.argv[i] for i in range(1,len(sys.argv))]
for input_pdf in argv:
basename_without_ext = os.path.splitext(os.path.basename(input_pdf))[0]
output_filename = "split_{}.pdf".format(basename_without_ext)
print("{}を2分割します。".format(os.path.basename(input_pdf)))
split_pdf(input_pdf, output_filename)
if __name__ == '__main__':
main()
引数を取得して、for文で回してsplit_pdfに渡します。出力ファイル名は入力ファイル名の先頭にsplit_を付けたものになります。