もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

pythonとphpでPDFを作成するにはどっちが使いやすいの?

参考サイト

はじめに

こんにちは。

今週全くブログを書けておらずめちゃめちゃ焦っている僕です。

仕事が忙しくて書けなかったのです。。。

でも仕事が忙しいからっていって、結局書けずじまいというのは絶対に嫌だったので、頑張って時間作って書こうと思います。

@kakakakakkuさんも言ってるしね。忙しくてブログ書けませんでした。とは言わないぞ!

今回は前回と似たようなものので、pythonのPDFライブラリPyPDF2 + PdfFormFillerPHPtcpdf + fpdfどっちが使いやすいの??っていう検証です。

前回はエクセルの取扱で比べたのですが、PDFもwebサービスやってるとよく使われる機能だったりするので、今回も調べてみました。

環境

php

$ php -v
PHP 7.1.5 (cli) (built: May 22 2017 00:14:43) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.1.5, Copyright (c) 1999-2017, by Zend Technologies
    with Xdebug v2.5.3, Copyright (c) 2002-2017, by Der

python

$ python --version
Python 3.6.0 :: Anaconda 4.3.1 (x86_64)

事前準備

$ mkdir -p pdf_test/php
$ mkdir pdf_test/python

$ cd pdf_test/php/
$ composer require tecnickcom/tcpdf
$ composer require setasign/fpdi
$ composer require setasign/fpdi-tcpdf
$ composer require setasign/fpdf

$ pip install PyPDF2 pdfformfiller

今回はよくある、PDFにデータを書き込んで、ダウンロードさせる的な機能を想定して、ダウンロードさせる対象のPDFファイルを作成する部分までを検証しようと思います。

使用するPDFのテンプレートは、とりあえず簡単な職務経歴書的なのを作ってみました。

このテンプレートPDFをtest_pdf_template.pdfとして、それぞれ先程作った、pdfフォルダ、pythonフォルダに置いておきます。

f:id:kojirooooocks:20180310223838p:plain

php

では早速php側やってみます。

<?php

require_once './vendor/autoload.php';

$pdf = new \setasign\Fpdi\TcpdfFpdi("L");
$pdf->setSourceFile(realpath(__DIR__) . '/test_pdf_template.pdf');

var_dump($pdf);

一旦これで読み取れるかを実験したところ、早速エラー

$ php sample.php 
PHP Fatal error:  Uncaught setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException: This PDF document probably uses a compression technique which is not supported by the free parser shipped with FPDI.

調べてみると結構同じような罠に引っかかっている人がいるようでした。

PDFが圧縮されているからフリー版のFPDIでは扱えないということらしいのですがそのためだけにacrobatを落とすの辛いなと思い、調べてると以下のサイトで再圧縮を書けてたところ、うまく読み取れました。

よかったよかった。

https://smallpdf.com/jp/compress-pdf

では改めて。

sample.php として以下を作成します。

<?php

require_once './vendor/autoload.php';

$template_path = realpath(__DIR__) . '/test_pdf_template.pdf';
$output_path   = realpath(__DIR__) . '/out.pdf';
$pdf = new \setasign\Fpdi\TcpdfFpdi("L");
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdf->setSourceFile($template_path);
$pdf->addPage();
$importPage = $pdf->importPage(1);
$pdf->useTemplate($importPage, 0, 0);

// 開発期間
$pdf->SetFont("az", "", 7);
$pdf->SetXY(14, 79, true);
$pdf->MultiCell(0, 0, "2018/01/01 〜 <br />2018/01/31", 0, "J", false, 1, '', '', true, 0, true);
$pdf->SetXY(14, 88, true);
$pdf->MultiCell(0, 0, "2018/02/01 〜 <br />2018/02/28", 0, "J", false, 1, '', '', true, 0, true);
$pdf->SetXY(14, 98, true);
$pdf->MultiCell(0, 0, "2018/03/01 〜", 0, "J", false, 1, '', '', true, 0, true);
// 業務内容
$pdf->SetFont("kozminproregular", "", 12);
$pdf->Text(50, 79, "API開発");
$pdf->Text(50, 88, "ユーザー登録画面開発");
$pdf->Text(50, 96, "管理画面開発");

// 担当箇所
$pdf->Text(110, 79, "バックエンドのみ");
$pdf->Text(110, 88, "バックエンド & フロント");
$pdf->Text(110, 96, "バックエンド & フロント");

// 人数
$pdf->Text(188, 79, "2");
$pdf->Text(188, 88, "1");
$pdf->Text(188, 96, "4");

// ポジション
$pdf->Text(202, 79, "PG");
$pdf->Text(202, 88, "PG");
$pdf->Text(202, 96, "PG");

// 開発環境
$pdf->SetFont("kozminproregular", "", 7);
$pdf->SetXY(222, 79, true);
$pdf->MultiCell(0, 0, "PHP7.1, MySQL5.7, Apache2.4<br />Redis, Git", 0, "J", false, 1, '', '', true, 0, true);
$pdf->SetXY(222, 88, true);
$pdf->MultiCell(0, 0, "PHP7.1, MySQL5.7, Apache2.4<br />Redis, Git", 0, "J", false, 1, '', '', true, 0, true);
$pdf->SetXY(222, 96, true);
$pdf->MultiCell(0, 0, "PHP7.1, MySQL5.7, Apache2.4<br />Redis, Git", 0, "J", false, 1, '', '', true, 0, true);

$pdf->Output($output_path, "F");

実行します。

$ php sample.php 

f:id:kojirooooocks:20180310224016p:plain

出来てました。これくらいのPDFならば実行速度は早いですね!

python

pythonやってみます。

phpと同じく、sample.pyを作成してやってみます。

PHPの場合はTCPDFが内部で持っている kozminproregular というフォントを使用していましたが、pythonの場合はネットで落として用意しました。

↑のフォントを同ディレクトリに置いて作業します。

# coding: utf-8
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from pdfformfiller import PdfFormFiller

# 準備(フォント設定、テンプレート読み込みなど)
pdfmetrics.registerFont(TTFont('VL-Gothic-Regular', './python/VL-Gothic-Regular.ttf'))
sty = ParagraphStyle('sty', alignment=TA_CENTER, fontName='VL-Gothic-Regular', fontSize=9)
filler = PdfFormFiller("./python/test_pdf_template.pdf")

# 開発期間
filler.add_text(u"2018/01/01〜<br />2018/01/31", 0, (40, 221), (110, 250), sty)
filler.add_text(u"2018/02/01〜<br />2018/02/28", 0, (40, 245), (110, 275), sty)
filler.add_text(u"2018/03/01〜", 0, (40, 275), (110, 310), sty)

# 業務内容
filler.add_text(u"API開発", 0, (120, 225), (300, 250), sty)
filler.add_text(u"ユーザー登録画面開発", 0, (120, 250), (300, 275), sty)
filler.add_text(u"管理画面開発", 0, (120, 275), (300, 310), sty)

# 担当箇所
filler.add_text(u"バックエンドのみ", 0, (320, 225), (500, 250), sty)
filler.add_text(u"バックエンド & フロント", 0, (320, 250), (500, 275), sty)
filler.add_text(u"バックエンド & フロント", 0, (320, 275), (500, 310), sty)

# 人数
filler.add_text(u"2", 0, (480, 225), (600, 250), sty)
filler.add_text(u"1", 0, (480, 250), (600, 275), sty)
filler.add_text(u"4", 0, (480, 275), (600, 310), sty)

# ポジション
filler.add_text(u"PG", 0, (540, 225), (640, 250), sty)
filler.add_text(u"PG", 0, (540, 250), (640, 275), sty)
filler.add_text(u"PG", 0, (540, 275), (640, 310), sty)


# 開発環境
filler.add_text(u"PHP7.1, MySQL5.7, Apache2.4<br />Redis, Git", 0, (615, 223), (770, 243), sty)
filler.add_text(u"PHP7.1, MySQL5.7, Apache2.4<br />Redis, Git", 0, (615, 247), (770, 267), sty)
filler.add_text(u"PHP7.1, MySQL5.7, Apache2.4<br />Redis, Git", 0, (615, 270), (770, 290), sty)

filler.write('./python/output.pdf')

f:id:kojirooooocks:20180310224036p:plain

問題なし!

こちらも速度的には全く問題ない感じでした。

やってみて

どちらも、速度・結果ともに問題なしでした。

ただ、python(というか使用したライブラリ?)のほうが、より直感的にかけるイメージでした。

改行も
だし。

phpも一応しらべて
での改行を認識する書き方をしましたが、見ての通りコードのわかりやすさはpythonの方です。

あと、こちらも使用したライブラリによるかもしれませんが、pythonの方は、PHP側で起きた PDFが圧縮されているから読み込めない というエラーは起きず、php側でエラーが起きたPDFでも問題なく開いて編集ができました。

勉強になりました。

次は画像処理とかをpythonphpで比べてみたいと思いまっす!