LuaLaTeX で pdfx パッケージを使い PDF/A に準拠した PDF を作る

> これは「[TeX ＆ LaTeX Advent Calendar 2020](https://adventar.org/calendars/5111)」の 1 日目の記事です。2 日目は[bd_gfngfn](https://adventar.org/users/15589)さんの記事の予定です。

本記事は LuaLaTeX で pdfx パッケージを使い PDF/A に準拠した PDF を作る方法を紹介します。台風で中止となり幻に終わった[TeXConf 2019](https://texconf2019.tumblr.com/)一般講演「[原ノ味フォントと ToUnicode CMap](https://github.com/trueroad/tr-TeXConf2019)」のアブストラクトや発表資料を PDF/A-2u 準拠にするためにやったことをまとめ、TeXLive 2020 環境で動作するように更新したものです。

## はじめに

PDF/A は長期保存を目的としたPDFの規格です。PDF/A に準拠した PDF は、現在の PDF ビュアー（たとえば Adobe Acrobat Reader DC 2020）だけでなく、将来リリースされる PDF ビュアーにおいても、同じように表示したり、同じように取り扱ったりできることが期待できます。印刷を前提とせず、PDFをファイルのまま扱って、どんな環境でも同じように表示したり取り扱ったりできるし、長期間保存後の将来の未知の環境でも同じように表示したり取り扱ったりできる、ということになろうかと思います。

似たような規格に PDF/X というものもあり、こちらは印刷目的の規格です。[TeX ＆ LaTeX Advent Calendar 2018](https://adventar.org/calendars/3382)の 14 日目に[p_typo](https://adventar.org/users/2072)さんの「[LuaLaTeXでPDF/X-4やPDF/X-1aなPDF生成する](https://note.mu/yuw/n/n4ac313f1b254)」など、PDF/X を作る解説記事をいくつか見たことがありますが、PDF/A を作る解説記事は少ないようです。昨年、試行錯誤した結果 LuaLaTeX で PDF/A を作ることができるようになったので、[TeXConf 2019](https://texconf2019.tumblr.com/)一般講演「[原ノ味フォントと ToUnicode CMap](https://github.com/trueroad/tr-TeXConf2019)」のアブストラクトや発表資料を PDF/A-2u 準拠にしてみました。これらのソース等は当時から公開済ですが、ここでどのようにしたのかまとめておきます。

## PDF/A とは

PDF/A は ISO 19005 規格になっているのですが、残念ながら規格書は有料なので私は見たことがありません。詳しいことは参考になりそうなサイトがいくつかあるので、そちらをご覧いただければと思います[^verapdf-doc]。一応、ベースになる PDF 規格に対して制限として、やらなければならないこと、やってはいけないこと、などを加えるものになっているようです。

[^verapdf-doc]: veraPDF のドキュメントは、規格書に書いてあることが何となく透けて見えるような感じがして、かなり参考になると思います。

最初に策定された PDF/A-1 (ISO 19005-1) は、PDF 1.4 規格をベースとしたものです。ベースの PDF 1.4 規格は ISO 規格になっていませんし、PDF 1.5 で導入されたオブジェクトストリームが使えないため圧縮率が悪く、電子署名も SHA-256 が PDF 1.6 以降でないと使えないので、少々苦しい感じがします。次に策定された PDF/A-2 (ISO 19005-2) は PDF 1.7 (ISO 32000-1:2008) をベースにしているので、オブジェクトストリームも使えますし SHA-256 で電子署名できますから、こちらの方がよさそうです。2020 年現在、PDF/A-3 (ISO 19005-3) まで策定されているようですが、これは PDF 1.7 ベースという点で PDF/A-2 と変わらないですし、LuaLaTeX で PDF/A を作る場合にいいことがあるわけでもなさそうです。

そこで、PDF/A-2 を作ることにします。PDF/A-2 は、さらに 3 種類に分かれます。そのうち一番条件が厳しい PDF/A-2a はタグ付き PDF でなければならないようで、LuaLaTeX で出力するのは難しそうです。残るは PDF/A-2b と PDF/A-2u なんですが、この違いは、テキストを Unicode で抽出できるか、要するに PDF からテキストをコピペできるか否かということになります。PDF/A-2b はテキスト抽出できなくて構いませんが、PDF/A-2u はテキスト抽出できなければなりません。そこで、テキスト抽出可能な PDF/A-2u を作ることにします。

## pdfx パッケージ

PDF/A を作るには[pdfx パッケージ](https://www.ctan.org/pkg/pdfx)を使います。pdfTeX, LuaTeX, XeTeX に対応していて、pTeX や upTeX では使えないため、普通に日本語を使うなら LuaTeX 一択ということになります。TeX Live に収録されていますので、TeX Live が使える環境であれば既にインストールされているハズです。

pdfx パッケージは「この PDF は PDF/A に準拠している」ことを示すメタデータを PDF に埋め込むことができるものですが、本当に準拠しているかどうかを保証することはできません。単に pdfx パッケージを使っただけだと、「この PDF は PDF/A に準拠している」と主張しているけど、実は全然準拠していない PDF になってしまっているかもしれません。そこで、PDF を作ったら、本当に PDF/A に準拠しているか否かを検証する必要があります。検証ツールにはオープンソースで配布されている[veraPDF](https://verapdf.org/)を使うことができますので、インストールしましょう。

## veraPDF

[veraPDF](https://verapdf.org/)は Java で書かれているので、Java の環境がなければ適当な OpenJDK をインストールしましょう[^openjdk]。

[^openjdk]: OpenJDK はいろいろなところが配布しているようなので、好きなものをインストールすればよいと思います。Linux 環境だったら、お使いの Linux ディストリビューションが提供している OpenJDK のパッケージをインストールするのが簡単だと思います。Windows や Mac では、OpenJDK インストールの解説記事があるようなので、そういうものを読んでもいいと思います。私は、今のところ Windows 環境で [Oracle OpenJDK のアーカイブ](http://jdk.java.net/archive/) から 11.0.2 (build 11.0.2+9) の Windows 64-bit の `openjdk-11.0.2_windows-x64_bin.zip` をダウンロードして、`C:\usr\local` に解凍し、使いたいときだけコマンドプロンプトで `PATH C:\usr\local\jdk-11.0.2\bin;%PATH%` を実行してパスを通してから使う（環境変数 `JAVA_HOME` は設定していませんが、とりあえず veraPDF のインストールと利用だけなら差し支えありませんでした）という方法を取っていますが、お勧めはしません。

OpenJDK がインストールできたら veraPDF をインストールしましょう。[veraPDF](https://verapdf.org/)のサイトを開いたら「Explore」をクリックします。すると一番上にいくつかのリンクが出るので、その中から「Software」をクリックします。すると「veraPDF for Windows」「veraPDF for Mac」「veraPDF for Linux」という 3 つのリンクが見えるので、そこからダウンロードしましょう[^verapdf-installer]。

[^verapdf-installer]: 3 環境分のリンクがありますが、どれも同じファイルを指しているように見えるんですよね…。

ダウンロードした `verapdf-installer.zip` を解凍して、中にあるインストーラを実行します。私は Windows 環境なので、コマンドプロンプトで `java.exe` に PATH を通し、`verapdf-install.bat` を実行しました。すると GUI でインストーラが起動するので、指示に従ってインストールすれば OK です[^verapdf-install]。

[^verapdf-install]: 私がダウンロードしたインストーラは veraPDF 1.16.1 のものだったので、インストール先の指定では「Browse」ボタンでフォルダ名指定ダイアログを出して `C:\usr\local` まで辿り、ダイアログ内を右クリックして「New Folder」を選択して新しいフォルダ `verapdf-1.16.1` を作成して、そこを選択しました。つまりインストール先は `C:\usr\local\verapdf-1.16.1` になります。また、インストールする packs は、デフォルト選択のまま（veraPDF GUI と veraPDF Batch files が必須で選択済、veraPDF Documentation が選択済、veraPDF Corpus and Validation model と veraPDF Sample Plugins が非選択）としました。

インストールできたら起動してみましょう。私は Windows 環境なので、コマンドプロンプトで `java.exe` に PATH を通してから、インストール先にある `verapdf-gui.bat` を実行します。以下のような画面になれば成功です。

![verapdf-installed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212298/7a47621a-7c80-d158-772e-87d200a4c018.png)

## TeX Live

TeX Live 2020 をインストールしておきましょう。本記事は TeX Live 2020 の、

* pdfx パッケージ Version 1.6.3 (2019-02-27)
* LuaTeX Version 1.12.0

を前提とします。

## PDF/A を作ってみる

以下のソース `simple.tex` を LuaLaTeX でコンパイルしてみます[^texlive2019]。

[^texlive2019]: TeX Live 2019 では `\pdfvariable omitcidset=1` を入れないと PDF/A-2 に準拠しませんでしたが、TeX Live 2020 なら入れなくても大丈夫です。

```simple.tex
% -*- coding: utf-8 mode:latex -*-

% PDF/A のメタデータ
\begin{filecontents*}{\jobname.xmpdata}
  \Title{タイトル}
  \Author{著者1\sep 著者2\sep 著者3}
  \Language{ja-JP}
  \Keywords{キーワード\sep きーわーど\sep key words}
  \Publisher{出版者}
\end{filecontents*}

\documentclass{ltjsarticle}

% pdfx.sty で PDF/A-2u の作成を指定
\usepackage[a-2u]{pdfx}

\begin{document}

\section{節}

本文。

\end{document}
```

以下のようにコンパイルします。2 回実行しているのは、pdfx パッケージが内部で hyperref パッケージを読み込んでおり、PDF の「しおり」あるいは「ブックマーク」と呼ばれる部分を正常に生成するためです。

```
$ lulalatex simple.tex
$ lulalatex simple.tex
```

すると、`simple.pdf` の他に、お馴染みの `simple.aux`, `simple.log` と、hyperref パッケージを使った際に出力される `simple.out` が出力され、さらに `simple.xmpdata`, `pdfa.xmpi` が生成されます。このうち、`simple.xmpdata` は、`simple.tex` の冒頭に記載した `filecontents*` 環境の中身が出力されたものですが、困ったことにこのファイルが存在すると `simple.tex` をコンパイルしても一切上書きしてくれないため、 `filecontents*` 環境の中身が更新されても変わってくれません。ですので、コンパイル前には `simple.xmpdata` を消すようにした方がいいでしょう。`pdfa.xmpi` はこの後の「メタデータ」で説明します。

## veraPDF で検証

`simple.pdf` が本当に PDF/A-2u に準拠しているか検証してみましょう。veraPDF を起動します。

![verapdf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212298/3d5e3e79-bc80-86f1-23ef-1b756f1f344e.png)

「Choose PDF」ボタンを押して `simple.pdf` を選び、「Execute」ボタンを押します。

![verapdf-compliant.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212298/4bfb48f3-1a96-49dc-474c-9c21f570d737.png)

少し待つと、結果として緑で「PDF file is compliant with Validation Profile requirements」と出てきてました。つまり PDF/A に準拠していることが確認できました。

詳細な結果を見るには「Reports」の中にある「View HTML」ボタンを押してみましょう。するとブラウザで「Validation Report」が表示されて、

```
Validation Profile:	PDF/A-2U validation profile
PDF/A compliance:	Passed
```

のような表示があり、PDF/A-2u の検証に通過したことがわかります。

一応、Poppler の pdfinfo でも確認してみましょう。

```
$ pdfinfo simple.pdf
（省略）
PDF version:    1.4
PDF subtype:    PDF/A-2u:2010
    Title:         ISO 19005 - Electronic document file format for long-term preservation (PDF/A)
    Abbreviation:  PDF/A-2
    Subtitle:      Part 2: Use of ISO 32000-1
    Standard:      ISO 19005-2
    Conformance:   Level U, Unicode support

$
```

これでも PDF/A-2u に準拠していることがわかりますね。でも、PDF version が 1.4 になっています。PDF 1.4 だと、オブジェクトストリームが使えませんし、SHA-256 で電子署名できません。

## pdfx で PDF バージョンを指定

pdfx パッケージのオプションで PDF バージョンを指定してみます。パッケージオプション `pdf17` を追加してあります。

```simple17.tex
% -*- coding: utf-8 mode:latex -*-

% PDF/A のメタデータ
\begin{filecontents*}{\jobname.xmpdata}
  \Title{タイトルあああ}
  \Author{著者1\sep 著者2\sep 著者3}
  \Language{ja-JP}
  \Keywords{キーワード\sep きーわーど\sep key words}
  \Publisher{出版者}
\end{filecontents*}

\documentclass{ltjsarticle}

% pdfx.sty で PDF/A-2u, PDF 1.7 の作成を指定
\usepackage[a-2u,pdf17]{pdfx}

\begin{document}

\section{節}

本文。

\end{document}
```

これをコンパイルして veraPDF で検証すると、ちゃんと PDF/A-2u に準拠していることがわかりました。ですが、 pdfinfo すると…

```
$ pdfinfo simple17.pdf
（省略）
PDF version:    1.4
PDF subtype:    PDF/A-2u:2010
    Title:         ISO 19005 - Electronic document file format for long-term preservation (PDF/A)
    Abbreviation:  PDF/A-2
    Subtitle:      Part 2: Use of ISO 32000-1
    Standard:      ISO 19005-2
    Conformance:   Level U, Unicode support

$
```

PDF 1.4 のままですね…。pdfx パッケージの PDF バージョン指定が効いてません…。これ、どうも pdfTeX や古い LuaTeX のプリミティブでバージョンを指定しようとしていて、現在の LuaTeX ではうまくいかないようです。そこで、現在の LuaTeX でも古い LuaTeX のプリミティブをエミュレーションする luatex85 パッケージを使います。

```simple17fix.tex
% -*- coding: utf-8 mode:latex -*-

% PDF/A のメタデータ
\begin{filecontents*}{\jobname.xmpdata}
  \Title{タイトルあああ}
  \Author{著者1\sep 著者2\sep 著者3}
  \Language{ja-JP}
  \Keywords{キーワード\sep きーわーど\sep key words}
  \Publisher{出版者}
\end{filecontents*}

\documentclass{ltjsarticle}

% LuaLaTeX で pdfx.sty の PDF バージョン指定が効くようにする
\usepackage{luatex85}

% pdfx.sty で PDF/A-2u, PDF 1.7 の作成を指定
\usepackage[a-2u,pdf17]{pdfx}

\begin{document}

\section{節}

本文。

\end{document}
```

これもコンパイルして veraPDF で検証すると、ちゃんと PDF/A-2u に準拠しています。そして pdfinfo してみると…。

```
$ pdfinfo simple17fix.pdf
（省略）
PDF version:    1.7
PDF subtype:    PDF/A-2u:2010
    Title:         ISO 19005 - Electronic document file format for long-term preservation (PDF/A)
    Abbreviation:  PDF/A-2
    Subtitle:      Part 2: Use of ISO 32000-1
    Standard:      ISO 19005-2
    Conformance:   Level U, Unicode support

$
```

ちゃんと PDF 1.7 になりましたね。

## PDF/A に違反してみる

さて、次は試しに PDF/A に準拠しない PDF を作ってみましょう。CMYK の色を使ってみます。

```cmyk.tex
% -*- coding: utf-8 mode:latex -*-

% PDF/A のメタデータ
\begin{filecontents*}{\jobname.xmpdata}
  \Title{タイトルあああ}
  \Author{著者1\sep 著者2\sep 著者3}
  \Language{ja-JP}
  \Keywords{キーワード\sep きーわーど\sep key words}
  \Publisher{出版者}
\end{filecontents*}

\documentclass{ltjsarticle}

% 色指定用
\usepackage{xcolor}

% LuaLaTeX で pdfx.sty の PDF バージョン指定が効くようにする
\usepackage{luatex85}

% pdfx.sty で PDF/A-2u, PDF 1.7 の作成を指定
\usepackage[a-2u,pdf17]{pdfx}

% カラーモデルを変換無しにする
\selectcolormodel{natural}

\begin{document}

\section{節}

{\color[cmyk]{1,0,0,0}C}
{\color[cmyk]{0,1,0,0}M}
{\color[cmyk]{0,0,1,0}Y}
{\color[cmyk]{0,0,0,1}K}

\end{document}
```

これをコンパイルすると、 pdfinfo では、以下の通り PDF/A-2u に準拠している、となります。

```
$ pdfinfo cmyk.pdf
（省略）
PDF version:    1.7
PDF subtype:    PDF/A-2u:2010
    Title:         ISO 19005 - Electronic document file format for long-term preservation (PDF/A)
    Abbreviation:  PDF/A-2
    Subtitle:      Part 2: Use of ISO 32000-1
    Standard:      ISO 19005-2
    Conformance:   Level U, Unicode support

$
```

ですが、 veraPDF で確認してみると…。

![verapdf-not-compliant.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212298/f0bc0283-2c3d-091b-1e63-5bf5eee6c581.png)

赤で「PDF file is not compliant with Validation Profile requirements」と出ました。「View HTML」ボタンを押すと、規格のどの項目を満たしていないのか、などが表示されます[^verapdf-varidation]。

[^verapdf-varidation]: どうやら規格書の文言を引用しているようなので、規格書が読めなくてもかなり参考になります。

この PDF は、pdfinfo では PDF/A-2u 準拠と出ますし、Adobe Acrobat Reader で開くと「このファイルは PDF/A 規格に準拠している可能性があり、…」などと表示されますが、これは PDF に含まれているメタデータが PDF/A-2u に準拠していますと名乗っているだけ、ということです。veraPDF で本当に準拠しているか確かめてみると、全然準拠しておらず PDF/A 違反であることがわかります。

この例では CMYK を使ったので違反になりましたが[^pdfa-cmyk]、他にも引っかかるところはいろいろとあるようなので、PDF/A を作ったら必ず検証した方がよいでしょう。

[^pdfa-cmyk]: PDF/A で CMYK が禁止されているわけではありません。pdfx パッケージはデフォルトで sRGB のカラープロファイルを埋め込むのですが、CMYK を使うとこれと矛盾するために違反になるようです。

また、`\includegraphics` で図として PDF を挿入する場合、その PDF で PDF/A 違反になるようなことをしている（例えば RGB と CMYK を両方使っている）と、それを読み込んだら PDF 全体としても PDF/A 違反になってしまいます。LuaTeX も pdfx パッケージも、特に準拠になるように変換してくれませんから、事前に違反にならないような図 PDF を用意しておく必要があります。カラーモデルの変換程度であれば、Ghostscript を使えばできます。例えば、CMYK の figure_cmyk.pdf を RGB の figure_rgb.pdf に変換するなら、以下のようにします。

```
$ gs -dSAFER -dBATCH \
	-dNOPAUSE -dNOCACHE -sDEVICE=pdfwrite \
	-dCompatibilityLevel=1.7 \
	-dColorConversionStrategy=/RGB \
	-dProcessColorModel=/DeviceRGB \
	-sOutputFile=figure_rgb.pdf \
	figure_cmyk.pdf
```

同じく、Gray の figure_gray.pdf に変換するなら、以下のようにします。

```
$ gs -dSAFER -dBATCH \
	-dNOPAUSE -dNOCACHE -sDEVICE=pdfwrite \
	-dCompatibilityLevel=1.7 \
	-dColorConversionStrategy=/Gray \
	-dProcessColorModel=/DeviceGray \
	-sOutputFile=figure_gray.pdf \
	figure_cmyk.pdf
```

## メタデータ

pdfx パッケージは、PDF/A に関するメタデータを PDF に埋め込みます。XMP と呼ばれる形式になっていて、LuaLaTeX 実行時に生成される `pdfa.xmpi` ファイルに埋め込んだ内容が保存されています。また、PDF になっていても pdfinfo を使って以下のようにして取り出すことができます。

```
$ pdfinfo -meta simple17fix.pdf
```

試しに、`pdfa.xmpi` と pdfinfo の出力で diff を取ってみましたが、最後の改行以外はまったく同じでした。

さて、この XMP ですが、中身を見てみると PDF/A を作りたい「だけ」ならあまり関係なさそうな PDF/X や PDF/UA のことが書いてあるなど、余計なところもありそうです。また、XMP は一つの PDF につき一つしか入れられないため、PDF/A 以外のメタデータも含ませたい場合[^cc-xmp]には、うまい具合にマージしてやる必要があります。そこで、この XMP メタデータをカスタマイズする方法をご紹介します。

[^cc-xmp]: 例えば、Creative Commons のメタデータを入れたい、等。

pdfx パッケージは、自分が持っている `pdfa.xmp` を元に XMP メタデータを生成します。`pdfa.xmp` がどこにあるかは、以下のコマンドで探すことができます。

```
$ kpsewhich pdfa.xmp
/usr/share/texmf-dist/tex/latex/pdfx/pdfa.xmp

$
```

この場合は、`/usr/share/texmf-dist/tex/latex/pdfx/pdfa.xmp` にあります。中を覗いてみると、XMP のベースになる内容と `\ifx` など TeX 言語で置き換えやらなにやらの制御をしているような感じの記述が混ざっているのが見えます。

つまり、pdfx パッケージの XMP メタデータは以下の方法で生成されているようです。まず、`simple17fix.tex` をコンパイルすると、冒頭の `filecontents*` 環境の中身が `simple17fix.xmpdata` として出力されます。pdfx パッケージは、この `simple17fix.xmpdata` と自分が持っている `pdfa.xmp` を処理することでマクロの置き換えなどによりタイトルや著者などを XMP へ反映、その結果を `pdfa.xmpi` に出力し、これを XMP メタデータとして PDF に埋め込んでいるようです。

ということは、カレントディレクトリにカスタマイズした `pdfa.xmp` を置いておけば、そっちを使ってくれるのでは？ということでやってみたところうまくいきました。「[原ノ味フォントと ToUnicode CMap](https://github.com/trueroad/tr-TeXConf2019)」のアブストラクトや発表資料では、使わなそうなところを削除し、Creative Commons のメタデータを混ぜています。ソースの中にカスタマイズした `pdfa.xmp` と、元の pdfx パッケージが持っていた `pdfa.xmp` との差分を `pdfa.xmp.diff` として置いてありますのでご興味があればご覧ください。

どのようにカスタマイズするかは、XMP の仕様を調べる必要があります。探すといくつか読めるものがあるようなので、参考にするとよいと思います。何をどう置き換えるか考えるには TeX 言語の知識も必要になりそうです。また、いじりすぎるとおかしくなるので、作った PDF を veraPDF で確認する必要があるでしょう。もちろん veraPDF で確認できるのはあくまでも PDF/A として問題ないか否かだけなので、PDF/A とは関係ない部分に問題があっても検出してくれないでしょう。

## おわりに

本記事は LuaLaTeX で pdfx パッケージを使い PDF/A に準拠した PDF を作るとともに、正しく PDF/A に準拠しているか否か検証する方法を紹介しました。PDF/A に準拠させるには少々手間がかかりますが、PDF/A は長期間保存後の将来の未知の環境でも同じように表示したり取り扱ったりできる、ことが期待できます。資料として保管する PDF については PDF/A に準拠させることが重要になってくるものと思いますので、本記事がそのお役に立てれば幸いです。