やったこと
AWS LambdaでPythonからgsコマンドを呼んでPDFを結合しました。
経緯
PythonのPyPDF2を使って結合しようとしましたが
PyPDF2はPDFのファイル構造がPDFのbasicなファイル構造(つまりheaderがあって、bodyがあって、Cross-reference Tableがあって、Trailerがあるみたいなもの)を前提としていて、Cross-reference TableがないとかTrailerがないPDFファイルを結合しようとするとエラーになってしまっていました。
gsコマンドならいけたので、LambdaでPythonからgsコマンドを呼ぶことにしました。
環境
AWS Lambda Python3.7
解決
Pythonからlsコマンドとかを叩くのはsubprocessモジュールを使ってできるので、lambdaの実行環境のデフォルトから実行できるコマンドなら以下のような感じで十分
out = subprocess.run(['ls'], stdout=subprocess.PIPE)
print(out.stdout.decode())
これで済めば話は簡単なのですが、ghostscriptはlambda実行環境では用意されてない(昔はあったみたいだけど今はなくなってるっぽいhttps://aws.amazon.com/jp/amazon-linux-ami/2018-03-packages/ )のでバイナリを持ってきてパスを通す必要がある。
$ curl -L -# https://github.com/ArtifexSoftware/ghostpdldownloads/releases/download/gs950/ghostscript-9.50-linux-x86_64.tgz -O
でバイナリファイルを入手する
$ tar zxvf ghostscript-9.50-linux-x86_64.tgz
で解凍したghostscript-9.50-linux-x86_64の中にgs-950-linux-x86_64ってのがあるのでこれをgsに名前を変えてlambda関数と同レイヤーにbinディレクトリでも作ってその中に入れる。
そしてzipで圧縮して、lambdaへ反映させる。
lambda関数のgsを呼ぶ部分は以下のような感じ
os.environ['PATH'] = os.environ['PATH'] + ':/var/task/binary'
cmd = [
"gs",
"-dBATCH",
"-dNOPAUSE",
"-q",
"-sDEVICE=pdfwrite",
"-sOutputFile=out.pdf",
"a.pdf",
"b.pdf"
]
out = subprocess.run(cmd, stdout=subprocess.PIPE)
print(out.stdout.decode())
雑談
https://www.slideshare.net/field-works/pdf-29001511
古いけどこのスライドが言うにはAdobe Readerは間違ったPDFに寛容らしく、間違ったPDFを生成するツールが世の中に氾濫しているってさ
やめてほしい