PHP+FPDI+TCPDFでPDFデータを処理する
この記事は2022/02/02に作成されました。
PHP上でPDFを処理する場合、「FPDI」及び「TCPDF」というライブラリを使用して行うケースが多いです。
主にFPDIではファイルの読み込みを、TCPDFではファイルの出力を行います。
これらライブラリには多くの機能がありますが、今回は内容を絞って
「PDFの読み込み→文字・画像の描画→データの出力」までを紹介します。
事前の諸注意
最初に注意すべき点として、PDFファイルは内部的にバージョン情報を持っていますが
FPDIはフリー版を利用する場合Ver1.5以上のPDFファイルを読み込む事ができません。
FPDIを利用してVer1.5以上のファイルを読み込みたい場合は、ライセンスを購入する必要があります。
以下のURLから読み込みのチェックが可能です。
https://www.setasign.com/products/fpdi-pdf-parser/details/
フリー版を利用する場合、例えば「事前に運営側がPDFをテンプレートとして用意しておく」…といった運用をするのであればバージョンの低いPDFを用意しておけば問題ありませんが、
ユーザーにPDFをアップロードしてもらう場合、当然バージョンが低いPDFを用意してくれるとは限らない・それを求めるのも大変という事で、PDFのバージョンをチェックする機能を用意する必要があります。
利用できないPDFがアップロードされた際、何か返り値があるわけではなく例外エラーを出力するので
try/catchなどを利用して判定機能を作成する必要があります。
余談として、PDFのバージョンを下げたい場合は
- adobe acrobat proでPDFを開く
- ファイルから「印刷」を選択
- プリンターを「Adobe PDF」に変更
- プロパティから「PDF設定」の「編集」を選ぶ
- Acrobat 4.0(PDF1.4)を選択
- 名前をつけて保存、印刷(PDFで出力)を行
という手順を組む事で可能です。
FPDIとTCPDFをロードして初期設定を行う
事前に設置したFPDIとTCPDFをPHP上で読み込みます。
zip版とcomposer版がありますので、好きな方を利用しましょう。
機能としては本当にたくさんあるのですが、
今回はPDF上に文章・画像を追加して書き出すまでに必要な最低限の設定を利用します。
まず初期設定として以下のコードを利用します。
コード | 機能 |
setSourceFile(string) | 利用するファイルを読み込む。 この時、無料版ではVer1.5以上のデータを利用するとエラーになるのでtry/catchで制御したい。 |
SetMargins(float,float,float) | PDFページの上・左・右の余白を設定する。 指定しなかった場合は10mmとなる。 |
SetAutoPageBreak(boolean) | 自動改ページ機能のtrue/falseを判定する。これがtrueになっている場合、例えば最下段に文字を置いて自動改行が入った時に2ページ目にはみ出る。 |
setDisplayMode(mixed,string) | PDFがビューア上でどのように表示されるかの設定を行う。それぞれ、 fullpage/fullwidth/real/default (ページ全体表示/ウィンドウ幅に合わせる/実寸表示/ブラウザのデフォルト表示) single/continuous/two/default (PDFページを1枚ずつ表示/連続して表示 / 2列表示 / ブラウザのデフォルト表示) を選択します。 |
setPrintHeader(boolean) | PDFにデフォルトで存在するヘッダー余白を利用するか否か。 |
setPrintFooter(boolean) | PDFにデフォルトで存在するフッター余白を利用するか否か。 |
setFontSubsetting(boolean) | PDFファイルにフォントを埋め込むか否か。 |
最低限の構成として以下のコードを貼り付けておけばひとまずの設定は終了です。
以下はコードの例です。
require_once('./pdf/tcpdf/tcpdf.php');//tcpdfの読み込み
require_once('./pdf/fpdi/fpdi.php'); //fpdiの読み込み
$this->pdf->SetMargins(0, 0, 0); //余白は0
$this->pdf->SetCellPadding(0); //余白は0
$this->pdf->SetAutoPageBreak(false) //最下段に置いた文章が2ページ目にはみ出るような状態でも、
勝手に改ページはしない
$this->pdf->setDisplayMode('default'); // 表示は標準
$this->pdf->setPrintHeader(false); //ヘッダーなし
$this->pdf->setPrintFooter(false); //フッターなし
$this->pdf->setFontSubsetting(true); // フォントは埋め込む
PDFの読み込み,描画
以下、実際にPDFにデータを記載していきます。
TCPDF+FPDIでPDFを作成する際、初期状態だと「0ページのPDF」が作られた状態となっています。
この「0ページのPDF」にページを追加し、文字を載せ、必要であれば既存のPDFを乗せる…という形でPDFを生成します。
そのため、まずAddPageによって「1ページ目」を作り、また必要であれば2ページ目以降を追加していく必要があります。
コード | 機能 |
setSourceFile(string) | デフォルトで利用するPDFが存在する場合はこのメソッドで読み込む。 この時、取り扱えないPDFを読み込むとエラーを吐いて処理が終了するので注意。 返り値として、ページ数が入る。 |
AddPage() | PDFページを追加する。 ※上部に詳細を記載。 |
importPage(int) | 事前にsetSourceFileでPDFを読み込んでいると、importPageを利用して読み込んだPDFの特定ページを指定できる。 この下のuseTemplateと合わせて利用する。 |
useTemplate(string) | useTemplateの引数としてimportPageを利用する事で、読み込んだPDFファイルをページに当てはめる事ができる。 例:$this->pdf->useTemplate($this->pdf->importPage(1))とすると、 事前に読み込んだPDFの1ページ目を、これから生成するPDFの内容として 追加することができる。 返り値としてwidthやheightなどpdfのデータが返される。 |
SetFont(string,string,float) | 使用するフォント、フォントスタイル(太字など)、文字サイズ(数字)を設定。 利用できるフォントスタイルはB/I/U/D/空文字。(ボールド・イタリック・アンダーライン・打ち消し線・なにもなし) |
SetXY(float,float) | Writeで書き込むX座標とY座標を設定する。以降SetXYが更新されない限り、全てのWriteがこの座標になる。 |
Write(float,string,string,bool,string ) | 実際に文章を記述するための処理、 それぞれ、 行の高さ / 描画する文字 / リンクURL / 背景塗りつぶし設定 / テキスト揃え / を設定する。 テキスト揃えはL/C/R/J(左/中央/右/両端)の5項目から選択する。 |
Output(string,string) | PDFファイルを出力する。ファイル名とアウトプットの方法をI/D/F/S(ブラウザへの出力/ダウンロード/ローカルに保存/PDFファイルを文字列化して出力)で選択する。 |
実際のフロー(サンプル)
これまでのコードで最低限のPDF書き出しが可能です。 以下、サンプルとして「PDFを読み込んでページ数を書き込んで出力する」というサンプルコードを記載します。 こちらも、勿論ただのPHPで動いているので 途中別のライブラリやメソッドからデータを引っ張ってきたり各種計算を挟む事ができます。 また、TCDPF+PDFIにはこれ以外にも多くの機能がありますので、色々試してみましょう。
require_once('./pdf/tcpdf/tcpdf.php');//tcpdfの読み込み
require_once('./pdf/fpdi/fpdi.php'); //fpdiの読み込み
$this->pdf->SetMargins(0, 0, 0); //余白は0
$this->pdf->SetCellPadding(0); //余白は0
$this->pdf->SetAutoPageBreak(false) //2ページ目の突入はなし
$this->pdf->setDisplayMode('default'); // 表示は標準
$this->pdf->setPrintHeader(false); //ヘッダーなし
$this->pdf->setPrintFooter(false); //フッターなし
$this->pdf->setFontSubsetting(true); // フォントは埋め込む
$pages = $this->pdf->setSourceFile('ファイルURLを記載');//ファイルを読み込む。返り値でページ数を取得
$this->pdf->SetFont('kozminproregular', '', 12);// 日本語フォントを12pxでセットしておく
for ($i = 1; $i <= $pages ; $i++) {
$this->pdf->AddPage();//「ページの追加」を行う
$this->pdf->useTemplate($this->pdf->importPage($i)); //読み込んだファイルを実際にPDF上にインポートする。
$this->pdf->SetXY(intval($data['width'])/2, 210);//ページカウントの追加。中央・下部に追加する。
}
$this->pdf->Output('SAMPLE.pdf','D'); //データを出力する。
プログラマー/S.Y