【Laravel】TCPDF+FPDIでPDFに文字入れを行う

業務で `Laravel` のアプリケーションにおいて、**「既存のPDFファイルを読み込み、文字入れをした上でPDFファイルを出力する」** という実装を行ったので、備忘録としてまとめておきます。

## 使用するライブラリ

- **TCPDF**

PHPでPDFを生成できるライブラリ。
[https://github.com/tecnickcom/tcpdf](https://github.com/tecnickcom/tcpdf)

- ****FPDI****

既存のPDFを読み取り、TCPDFのテンプレートとして使用できるようにするライブラリ。
[Download the FPDI tool from ▷ setasign.com](https://www.setasign.com/products/fpdi/downloads/)

上記の2つのライブラリを使用するので、先にインストールしておきます。
※インストール方法については以下の記事を参照。
[【TCPDF+FPDI】PHPで領収書PDFに文字を出力する方法](https://hsmt-web.com/blog/php-pdf-output/)

## 実装の概要

全体の流れは以下の通りです。

【事前準備】
テンプレートとして使用するPDFを用意し、プロジェクトディレクトリに保存しておく。

【実装の流れ】
1.  `FPDI` インスタンスを生成し、テンプレートとなるPDFをセットする。
2. テンプレートのPDF上に、座標を指定して文字を乗せていく。
3. PDFファイルをブラウザに出力する。

では実際のコード例を挙げて説明していきます。

## 実装方法

## 1. PDFの初期設定

まずは `FPDI` インスタンスを生成し、テンプレートとなるPDFを指定、各種初期設定を行います。

```php
<?php

// 追記
use setasign\Fpdi\Tcpdf\Fpdi;

public function downloadPdf()
{
  // FPDIインスタンス生成
	$pdf = new Fpdi();

  // フォントの設定
  $pdf->SetFont('kozminproregular');
  // テンプレートとなるPDFファイルを指定（ファイルまでのパスを引数に渡す）
  $pdf->setSourceFile('template.pdf');
  // 新規ページをセット
  $pdf->addPage();
  // テンプレートPDFの1ページ目を読み込み
  $page = $pdf->importPage(1); 
  // 読み込んだページをテンプレートに使用
  $pdf->useTemplate($page); 
  // 各種初期設定
  $pdf->setFontSize(12);
  $pdf->setMargins(0, 0, 0);
  $pdf->setCellPadding(0);
  $pdf->setAutoPageBreak(true, 0);
  $pdf->setPrintHeader(false);
  $pdf->setPrintFooter(false);
}
```

## 2. テンプレートのPDFに文字入れを行う

PDFに文字入れをしていきます。

文字入れについては、以下3つの方法を紹介します。
用途に応じて使い分けるのが良いかと思います。

- **`Text`メソッド**
指定した座標に文字列を出力する。


- **`Cell` メソッド**
指定した座標にセルを表示し、セルの中に指定した文字列を出力することができる。
文字列は、センタリングもしくは左右どちらかに揃えて配置できる。（高さは中央に配置される）
文字列にリンクを貼ることもできる。


- **`MultiCell` メソッド**
 `Cell` メソッドの働きに加え、文字列がセルの右端に達すると改行してくれる。


※他にも使用できるメソッドは色々あります。
以下のサイトが分かりやすかったので是非見てみてください。

https://phpjavascriptroom.com/?t=php&p=fpdf_manual

### ツール紹介

上記のどのメソッドを使う場合でも、PDF上の座標を指定して文字列やセルを配置する必要があります。

座標を取得する方法は色々あるかと思いますが、私は `Adobe Acrobat Reader DC` を使いました。
[PDFリーダー | Adobe Acrobat Reader DC](https://www.adobe.com/jp/acrobat/pdf-reader.html)

PDFファイルを `Adobe Acrobat Reader DC` で開き、
「表示→表示切り替え→定規とグリッド→定規」（もしくはCtrl＋R）
とクリックしていくと、座標を示す定規が表示されます。

![定規.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1208065/b8b5cf03-d1d7-b2c8-b015-45dbf4b5c996.jpeg)


### `Text`メソッド

```php
$pdf->Text(x軸の座標, y軸の座標, 出力する文字列);
```

 `Text` メソッドの引数は以下の3つです。

・第1引数…基点のx軸の座標（左からの位置）
・第2引数…基点のy軸の座標（上からの位置）
・第3引数…出力する文字列

指定した座標を基点（文字列の左上）として、文字列が出力されます。

### `Cell` メソッド

 `Cell` メソッドを使う場合は、先に `SetXY` メソッドで基点とする座標を指定し、その位置に `Cell` メソッドでセルを設置します。
`Cell` メソッドでセルを設置することで、`Cell` メソッドの第3引数に指定した文字列も出力されます。

```php
$pdf->SetXY(x軸の座標, y軸の座標);
$pdf->Cell(幅, 高さ, 出力する文字列, (bool)セルの枠線の有無, セルを作った後のXY座標定義, 揃え, (bool)セルの塗りつぶし, リンク先URL);
```

 `Cell` メソッドは上記の通り、たくさん引数を指定することが出来ます。

使用していて感じたメリット・デメリットを下に挙げます。

【メリット】
 ・`Text` メソッドと比べて、セルの高さの中央に文字列を配置してくれるので便利。
・リンクを張ることも出来る。

【デメリット】
・文字列の長さがセルの幅を超えた場合でも、自動的に改行は行われない。

### `MultiCell` メソッド

 `Cell` メソッドの進化版のようなものと認識しています。
文字列の長さがセルの幅を超えた場合、自動的に改行を行ってくれます。

```php
$pdf->SetXY(x軸の座標, y軸の座標);
$pdf->Cell(幅, 高さ, 出力する文字列, (bool)セルの枠線の有無, 揃え, (bool)セルの塗りつぶし);
```

`Cell` メソッドと同様に、先に `SetXY` メソッドで基点とする座標を指定し、その位置に `MultiCell` メソッドでセルを設置します。

【備考】

・セルの中に複数行の文字列を出力する場合はこっちが便利。
・ `Cell` メソッドのデフォルトではセルの高さの中央に文字列を配置するが、`MultiCell` メソッドのデフォルトではセルの左上を基点として文字列を配置する。

### 3. PDFファイルをブラウザに出力する

最後に `Output` メソッドを使ってPDFファイルを出力します。

```php
$pdf->Output(); // 画面出力
```

`Output` メソッドの引数は以下の2つです。

・第1引数…ファイル名（指定しなければ `doc.pdf` という名前になる）
・第2引数…出力モード（`I`：ブラウザへ出力, `D` ：ファイルダウンロード, `F`：ローカルファイルとして保存, `S` ：文字列としてドキュメントを返す）

以上の手順で、既存のPDFに文字入れをしてPDFを出力することが出来ました。


## 参考記事

https://phpjavascriptroom.com/?t=php&p=fpdf_manual

https://hsmt-web.com/blog/php-pdf-output/

https://cpoint-lab.co.jp/article/202003/14287/

https://www.keibunsya.co.jp/modules/features/index.php?content_id=199

https://www.javadrive.jp/fpdf/cell/index8.html