Adobe Document Generation APIで動的なPDFを作成しよう

## Adobe Document Generation APIとは
[Adobe Acrobat Services](https://developer.adobe.com/document-services/) （2022年12月　Adobe Document Servicesという名前から名称が変更されました）はPDFに関する様々なAPIサービスを提供していますが、今回はこの中の１つ、[Adobe Document Generation API](https://developer.adobe.com/document-services/apis/doc-generation/)を紹介します。

### Adobe Document Generation API
Adobe Document Generation APIはテンプレートとテンプレートに差し込むデータから、PDF（またはWordドキュメント）を作成するAPIです。PDFの作成処理はクラウド上で行われます。テンプレートとなるドキュメントは、Wordドキュメント、データはJSON形式で用意します。従来、こういった動的なPDFを作る仕組みとして、[Apache FOP](https://xmlgraphics.apache.org/fop/) や[FreeMarker](https://freemarker.apache.org/) などのテンプレートエンジンが存在していますが、テンプレートとしてXSLやFreeMarkerを扱うのは少々面倒なところがあります。Document Generation APIはみんなが使い慣れているWordドキュメントと簡単なタグでテンプレートを作成できるので、直感的にデザインできます。

Document Generation APIは [REST API](https://developer.adobe.com/document-services/docs/apis/) で提供されていますので、プログラム言語に依存しないで利用できます。Java、.NET, Python, Node.js (JavaScript) をご利用の場合は [SDK](https://developer.adobe.com/document-services/docs/overview/pdf-services-api/#sdk) も用意されています。さらにPower Automateのアクションとしても用意されていますので、ローコードで開発し社内ですぐにご利用いただくことが可能です。

![power automate action.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111352/3495328f-5ee7-d25f-5b1e-36997564e202.png)

### ユースケース
業務の中で顧客データ等を元に定型的なアウトプットを繰り返しPDFとして出力する場合や、それらを大量に出力する場合に利用できます。例えば、イベントの招待状や、見積書、請求書、オファーレター、NDAなどの契約書など、利用用途は多岐に渡ります。

Document Generation APIの利用場面のヒントは、テンプレートの例として[こちら](https://developer.adobe.com/document-services/apis/doc-gen-api-template/)でもご覧いただけます（このページは英語ですが、日本語でもご利用いただけます）

## Hello Worldなサンプル
### 1. データの準備
データとして以下のようなものを使います。

``` json
{
    "name": "山田　太郎",
    "greeting": "こんにちは！"
}
```

今回のサンプルでは、直接コードの中にこのデータをセットします。

### 2. テンプレートの準備

次にWordのテンプレートを用意します。下の図のように後でデータを差し込む部分（タグ）を {{name}} のように表現します。タグに対してフォントのスタイルを適用すると、差し込まれたデータもそのスタイルが適用されるようになります。

![Basic Template.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111352/27c98891-5317-d1cc-1aeb-9868c51c1186.png)

Wordにアドインできる[Adobe Document Generation](https://developer.adobe.com/document-services/docs/overview/document-generation-api/wordaddin/)を使用すると、差し込むデータからタグを生成することができ、それを簡単に配置してテンプレートをデザインすることができます。数個のデータのタグを配置する場合であれば手動でも問題ないですが、データの構造が複雑な場合には便利です。

![document tagger.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111352/26b97f65-d5b0-a4db-6481-2063f7b47be9.png)


### 3. プログラミング（データとテンプレートを合体してPDFを出力）

上の２つの準備ができたら、後はAPIをを使っての簡単なプログラミングになります。今回はJavaのサンプルを提示します。実際にプログラムを書く前に準備が必要です。その１つはAPIを利用するにあたってのCredentialを取得しておく必要があります。
Credentialは、[Adobe PDF Services API](https://developer.adobe.com/document-services/apis/pdf-services/)のページから取得できます。Credentialの取得などDocument Services APIを利用してアプリケーションを書く準備については、以下の記事に丁寧に書かれておりますのでぜひご覧ください。

https://qiita.com/kurabaya/items/d8e6d0114ca5e5c7acfa

もう１つはプロジェクトの準備です。Credentialを取得するときに使用する言語としてJavaを指定すると、Mavenベースのサンプルプロジェクトがダウンロードできるので、これを利用するのが簡単です。Gradleでプロジェクトを作成する場合にはpdf-services-sdkを依存するライブラリとしてbuild.gradleにpdfservices-sdkを設定します。

``` gradle
dependencies {
    implementation 'com.adobe.documentservices:pdfservices-sdk:3.0.0'
    implementation 'org.slf4j:slf4j-api:2.0.3'
    implementation 'org.slf4j:slf4j-log4j12:2.0.3'
    testImplementation 'junit:junit:4.11'
}
```

取得したcredentialとprivate keyをプロジェクトの中に配置します。そしてアプリケーションの本体として、以下のようなコードを用意します。

```SimpleGenerationApiDemo.java
package com.adobe.demo;

import java.io.IOException;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.pdfservices.operation.ExecutionContext;
import com.adobe.pdfservices.operation.auth.Credentials;
import com.adobe.pdfservices.operation.exception.ServiceApiException;
import com.adobe.pdfservices.operation.io.FileRef;
import com.adobe.pdfservices.operation.pdfops.options.documentmerge.DocumentMergeOptions;
import com.adobe.pdfservices.operation.pdfops.DocumentMergeOperation;
import com.adobe.pdfservices.operation.pdfops.options.documentmerge.OutputFormat;


public class SimpleGenerationApiDemo 
{
    private static final Logger logger = LoggerFactory.getLogger(SimpleGenerationApiDemo.class);
    public static void main( String[] args )
    {
        // 差し込みデータの準備
        final JSONObject jsonData = new JSONObject("{\"name\": \"山田　太郎\",\"greeting\": \"こんにちは！\"}");

        logger.info("Insert data :{}", jsonData);
        
        try {
            // API Credentialの読み込みとインスタンス化
            Credentials credentials = Credentials.serviceAccountCredentialsBuilder()
                                        .fromFile("pdfservices-api-credentials.json").build();

            // ExecutionContextの作成
            ExecutionContext executionContext = ExecutionContext.create(credentials);
            
            // DocumentMergeOptionsの作成
            DocumentMergeOptions mergeOptions = new DocumentMergeOptions(jsonData, OutputFormat.PDF);
            
            // DocumentMergeOperationの作成。
            DocumentMergeOperation operation = DocumentMergeOperation.createNew(mergeOptions);

            // テンプレートの読み込み
            FileRef template = FileRef.createFromLocalFile("src/main/resources/document-template.docx");
            operation.setInput(template);

            // テンプレートと差し込みデータからPDFを生成
            FileRef result = operation.execute(executionContext);

            // ファイルとして保存
            result.saveAs("output/mergeOut.pdf");

        } catch (IOException|ServiceApiException ex) {
            ex.printStackTrace();
        }
    }
}
```
実行すると、JSONデータがWordのテンプレートに差し込まれて、mergeOut.pdfとして出力されます。

![mergeOut.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111352/99440ffe-9436-4bec-21b4-9148ef2bfd30.png)

サンプルコードはこちらです：https://github.com/bandetech/adobe-document-generation-api-sample

## 実用的なサンプル
少し実用的なサンプルとして、某製造会社の受発注システムでのデジタライゼーションでの適用例をご紹介します。この会社では従来FAXを使って発注者から注文を受け付けていました。工場の担当者は、FAXを受信後、社内の生産管理システムに注文を登録し、受注可能であれば納期とともに、受注確認書に印鑑を押して、発注者に返却するという流れで処理を行っていました。この方法では、工場の担当者は注文書を受領後、再度システムに情報を手入力するという作業など、無駄な手間やコストが発生していました。

![Before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111352/2e0d7c8c-b1c3-27e4-9d9d-48d285eb1623.png)

Webアプリケーションベースの新しい受発注システムによって、発注者はWebフォームに注文を入力、送信すると、PDF Services API (Document Generation API)でWebフォームに入力された情報を元にPDFで注文確認書を作成し、その控えを発注者に送付するようになっています。

![After.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111352/a7fb2cd9-580d-9c67-c0fa-17998b3de38d.png)

図中に、Adobe Acrobat Signが含まれていて、工場担当者が受注確認書に署名、送信する処理も含まれています。このAcrobat Signで使う署名欄の指定もタグで表現してテンプレートに配置できたりします。こちらについてはまた次回説明したいと思います。

先ほどのHello World的なサンプルではシンプルな文字列をPDFに出力するだけでしたが、Document Generation APIでは表の出力も可能です。例えば、注文を配列として持つデータ（以下ではorders）があったとき、

``` json
{
    "orderPerson": "山田　太郎",
    "orderDate": "2023年1月18日",
    "title": "出　荷　指　示　書　（控）",
    "orders": [
        {
            "deliveryMethod": "直接",
            "deliveryDate": "2023-01-18",
            "deliveryTime": "11:00",
            "deliveryTo": "アドビ株式会社",
            "dealer": "大崎支店",
            "product": "セメント",
            "shape": "P",
            "limitation": "",
            "net": "",
            "amount": "50",
            "orderNo": "12345",
            "fixedNo": "",
            "no": 1
        },
        {
            "deliveryMethod": "直接",
            "deliveryDate": "2023-01-18",
            "deliveryTime": "11:00",
            "deliveryTo": "XYZ株式会社",
            "dealer": "西大井支店",
            "product": "カーボン",
            "shape": "FC",
            "limitation": "",
            "net": "",
            "amount": "20",
            "orderNo": "12345",
            "fixedNo": "",
            "no": 2
        },
        {
            "deliveryMethod": "トラック",
            "deliveryDate": "2023-01-18",
            "deliveryTime": "11:00",
            "deliveryTo": "ABC株式会社",
            "dealer": "巣鴨支店",
            "product": "セラミック",
            "shape": "FC",
            "limitation": "",
            "net": "",
            "amount": "100",
            "orderNo": "12345",
            "fixedNo": "",
            "no": 3
        }
    ]
}
```
テンプレートとして次のものを用意するとします。
![Table Word Template.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111352/63e8540f-8a5d-f480-2ef7-e707556346a0.png)
すると、データのordersが要素の数に合わせてうまくテーブルの行が展開して、Document Generation APIが表を作成してくれます。

![pdf-out.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111352/3793351f-abe3-5b7b-7559-0434adfd61a8.png)

テンプレートで利用できるタグは、表の他に、リストや、図の埋め込み、条件による制御、デフォルト値、値の計算などもできるようになっています。詳しくは[こちら](https://developer.adobe.com/document-services/docs/overview/document-generation-api/templatetags/#numerical-calculations)をご参照ください。

YouTubeに全体のソリューションとデモを紹介しておりますので、合わせてご覧ください。
<br>
<iframe width="560" height="315" src="https://www.youtube.com/embed/lP58Jr3lLYk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

<br><br>
サンプルコードはこちらです：https://github.com/bandetech/shipping-instruction-demo

# 最後に
人を介するデジタルの情報をつなぐ役割としてのPDFは、B2B、B2Cを問わずなくてはならいものになっています。人が直接PDFを作成することもありますが、営業、経理、ECなどの業務システムから直接PDFが出力されて相手に渡されるトランザクションは圧倒的に多く、ペーパレス化が進む中、これからも増え続けていくでしょう。今回ご紹介したDocument Generation APIはテンプレートを簡単にデザインして、データを持っているシステムと組み合わせることで、高品質なPDF文書を効率的に作成することができます。