search
LoginSignup
11

More than 5 years have passed since last update.

posted at

updated at

重い PDF を Pythonista で軽量・分割した話

この記事は Pythonista Advent Calendar 2017 の9日目の記事です。

Pythonista でライフハックするための、小ネタを紹介します。

概要

P1030456.jpg

iPhone と Pythonista があれば、いつでもどこでもプログラミングが出来ます。
とは言えフリック入力で Python Syntaxを打ち続けるのは、エディタ支援があっても流石につらいので、

  1. Bluetoothキーボード
  2. バンカーリング

という最小限のギアを組み合わせて、ライフハックしています。

📱 実際にやってみると?

iPhone でプログラミングしてみて感じることは、

  1. 検索する時にiPhoneを手に持つと、Bluetoothペアリング状態でソフトウェアキーボードが隠れてつらい
  2. 画面サイズに限界のあるiPhoneで、ドキュメントを見ながらアプリを行ったり来たりするのはつらい

でした。iPad ProとSplitViewを使えば上記の問題を解決できますが、iPad Proは外に持ち出しません...

いろいろ試行錯誤して、眼を通したいページやドキュメントを PDF にして紙の資料にすれば、
解決できるのでは?と考えました。

📃 紙の資料にプリントする

iPhoneからPDFをプリントするアプリはいくつかありますが、
私は自宅にプリンターを所持していないので、コンビニでプリント出来るアプリをよく使っています。

ただ、そのアプリに送信出来るPDFのファイルサイズが6MBまでという制約があり、対処に困りました。
そのためだけにPDF分割のアプリをダウンロードしたり、Macでリサイズしてもう一度iPhoneに戻すのは、
あまりスマートではありません。

...

前置きが長くなりました。
この問題に対処するためにPythonistaを使って、PDFのファイルサイズを6MBまでに抑えて分割します。

🐍 Python で解決

# -*- coding: utf-8 -*-

import os
import appex

from PIL import Image
from PyPDF2 import PdfFileWriter, PdfFileReader

div = 6

def imageWriter(page0):
    xObject = page0['/Resources']['/XObject'].getObject()
    for obj in xObject:
        if xObject[obj]['/Subtype'] == '/Image':
            size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
            data = xObject[obj].getData()
            if xObject[obj]['/ColorSpace'] == '/DeviceRGB':
                mode = "RGB"
            else:
                mode = "P"
            if xObject[obj]['/Filter'] == '/FlateDecode':
                img = Image.frombytes(mode, size, data)
                img.save(obj[1:] + ".png")
            elif xObject[obj]['/Filter'] == '/DCTDecode':
                with open(obj[1:] + ".jpg", "wb") as img:
                    img.write(data)
            elif xObject[obj]['/Filter'] == '/JPXDecode':
                with open(obj[1:] + ".jp2", "wb") as img:
                    img.write(data)

def main():
    src = appex.get_file_path() 
    src = PdfFileReader(src, 'rb')
    items = [range(i, min(i + div, src.numPages)) for i in range(0, src.numPages, div)]

    if not os.path.exists('pdf'): 
        os.mkdir('pdf')

    for i, lst in enumerate(items):
        dst = PdfFileWriter()
        for j in lst:
            dst.addPage(src.getPage(j))
            with open('pdf/%03d.pdf' % i, 'wb') as out:
                dst.removeLinks()
                dst.write(out)

if __name__ == '__main__':
    main()

PyPDF2 内で余計なメタデータを削除・ページ数を分割することで、1ファイルあたりのサイズを6MBまで
軽量化しています。Pythonista Documents 内の pdf フォルダに書き出されます。

PILPyPDF2 はPythonista built-in モジュールなので、別途 pip インストールする
必要がありません。appex モジュールはPythonista用モジュールなので、他の環境では
os.path モジュールなどに読み替える必要があります。

まとめ

ポケットに収まるサイズ感でモバイルハック出来るのがPythonista最大のメリットなので、
工夫次第でなんでも出来そうです。カフェの小さなテーブルでも邪魔にならないサイズ感です☕

日常の小さな問題を解決する手段としての、Pythonの小ネタの紹介でした。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
11