LaTeXで出力PDFのバージョンを指定する ～bxpdfverパッケージ～

>   これは「[TeX/LaTeX Advent Caleandar 2020](https://adventar.org/calendars/5111)」の11日目の記事です。
>   （10日目は [CareleSmith9 さん](http://circle9tym.blog.fc2.com/blog-entry-379.html)、12日目は [abenori さん](https://abenori.blogspot.com/2020/12/futurelet.html)です。）

「[アドベントカレンダーが埋まらない](https://twitter.com/zr_tex8r/status/1332488734059556864):cry:」という緊急事態発生につき、急遽、拙作のチョットスゴイ（かもしれない）パッケージである**[bxpdfverパッケージ][bxpdfver]**についての50分で書き殴った解説記事を放出します:upside_down: 

[texadvent]: https://adventar.org/calendars/5111
[bxpdfver]: https://www.ctan.org/pkg/bxpdfver

## bxpdfverパッケージのここがスゴイ！

LaTeXでPDFファイルを出力するには次の2通りの方法[^dvips-1]があります。

[^dvips-1]: ん、dvips？ なにそれ？

* DVI出力のエンジン（LaTeX、pLaTeX、upLaTeX）とdvipdfmxを組み合わせる
* PDF出力のエンジン（pdfLaTeX、XeLaTeX、LuaLaTeX）を使う

最近のTeX Liveにおいては、どちらの工程を用いた場合も**出力されるPDFのバージョンは1.5**となります。

しかし、**出力PDFのバージョンを変えたい**場合があります。例えば次のような場合です。

* 後の工程でPDFを加工する必要があり、そのためのソフトウェアがPDF-1.4にしか対応していないため、出力PDFバージョンを1.4にする必要がある。
* 文書中でPDF-1.6の画像を挿入しているため、出力PDFバージョンを1.6（以上）にする必要がある[^include]。

[^include]: LaTeXの工程における「PDF画像の挿入」は単に対象のPDFのコードをそのまま埋め込むだけ（再レンダリングはしない）なので、PDF-1.6の機能を含む画像を埋め込んだときにそれが正しく処理されるためには、大本のPDFのバージョンをそれ以上にする必要があります。

dvipdfmxを用いる場合は、起動時のオプションで出力PDFバージョンを指定できます。

```bash
# 出力PDFバージョンを1.4にする
dvipdfmx -V 4 report.dvi
```

また、TeX言語レベル:scream:の機能を使えば文書中で出力PDFバージョンを指定することもできます。PDF出力エンジンの場合は、当然[^indocument]文書中で指定することになるのですが、エンジンごとに指定の方法が異なっていてイロイロ厄介です:sob: 

[^indocument]: エンジンが直接PDFを出力しているので、設定を書き込む場所はTeX文書内しかありえません。

この**「出力PDFバージョンの**（文書内での）**指定」**を**LaTeXレベルで**行うためのパッケージが[bxpdfver]です。

PDFバージョン指定の他にも「PDFストリームの圧縮を行うか」などの様々な**「出力PDFの性質」を指定する**機能ももっています。

## 使ってみる

bxpdfverパッケージは以下のエンジン／DVIウェアに対応しています。

* DVI出力エンジンとdvipdfmxの組み合わせ。
* pdfLaTeX／XeLaTeX／LuaLaTeX。

※dvipsには非対応です[^dvips-2]。

[^dvips-2]: 実際のところ、dvipsを使ってDVI→PS→PDFと変換する工程の場合、出力PDFバージョン等は「PS→PDFの変換を行うソフトウェア」の設定に委ねることになり、それはLaTeX文書中では指定できないはずです。

### パッケージ読込

dvipdfmxを使う場合には、**ドライバ指定**（`\documentclass`に[^global]`dvipdfmx`オプションを付ける）が必要です。

[^global]: `\usepackage[dvipdfmx]{bxpdfver}`のようにパッケージにドライバオプションを指定することも可能ですが、イマドキのLaTeXでは**ドライバオプションはグローバルに指定する**お約束になっています。

```tex
% 例えばupLaTeX+dvipdfmxの場合
% ↓dvipdfmxオプションをつける
\documentclass[uplatex,dvipdfmx,a4paper]{jsarticle}
\usepackage{bxpdfver}
```

PDF出力エンジンの場合はドライバ指定は不要です。

```tex
% 例えばLuaLaTeXの場合
\documentclass[a4paper]{ltjsarticle}
\usepackage{bxpdfver}
```

### 出力PDFバージョンを指定する

`\setpdfversion`命令で指定します。引数はバージョン値で、有効な値[^versions]は`1.4`・`1.5`・`1.6`・`1.7`・`2.0`です。

[^versions]: PDFの実在のバージョンで1.4以降のものはこれが全てです。

```tex
% 出力PDFバージョンを1.7にする
\setpdfversion{1.7}
```

あるいは、パッケージ読込時にオプションでも指定できます。

```tex
% 出力PDFバージョンを1.7にする
\usepackage[1.7]{bxpdfver}
```

### 出力PDFバージョンを挿入画像と同じにする

`\setpdfversion`命令の引数にPDFファイル名を指定すると、そのファイルのPDFバージョンが出力バージョンに指定されます。

```tex
% 出力PDFバージョンをimage.pdfと同じにする
\setpdfversion{image.pdf}
```

※パッケージオプションではファイルでのパージョン指定はできません。

### ストリームの圧縮を抑止する

`\suppresspdfcompression`命令を実行するとPDF内部のストリームデータの圧縮が抑止されます。「PDFチョットデキル」ような人が「LaTeXの出力したPDFの中のコードを調査したい」という場合に有用です。

```tex
% ストリームの圧縮を抑止する
\suppresspdfcompression
```

パッケージオプション（`nocompress`）でも指定できます。

```tex
% ストリームの圧縮を抑止する
\usepackage[nocompress]{bxpdfver}
```

※dvipdfmxのコマンド行オプションの`-z 0`の指定と等価です。

### オブジェクトストリームの使用を抑止する

`\suppresspdfobjcompression`命令[^objcompress]を実行すると「出力コード中でオブジェクトストリームが使われなくなり、全般的[^keepversion]にPDF-1.4以前の古い書式が使われる」ようになります。「PDF自信ニキ」のための機能です。

[^keepversion]: もちろん`\suppresspdfobjcompression`は「PDFのバージョン」自体には影響しません。バージョンが1.5以上のPDFでも古い書式は使えます。なお、バージョンが1.4の場合は無条件に古い書式が使われます。

[^objcompress]: `objcompression`という名称はpdfTeXのプリミティブの`\pdfobjcompresslevel`に由来します。実際は「オブジェクトストリーム」はそれ自体は圧縮とは関係ありません（圧縮の効率を高めるための機構ではありますが）。


```tex
% オブジェクトストリームを抑止する
\suppresspdfobjcompression
```

パッケージオプション（`noobjcompress`）でも指定できます。

```tex
% オブジェクトストリームを抑止する
\usepackage[noobjcompress]{bxpdfver}
```

### PDF中の数値データの精度を指定する

使う機会はほぼないと思いますが、これで不具合が回避できる場合があったらしいです。

```tex
% 数値データを小数第4位まで出力する
\setpdfdecimaldigits{4}
```

※dvipdfmxのコマンド行オプションの`-d <整数>`の指定と等価です。

### PDF内部のアンカー名を保持する

hyperrefパッケージを使うとPDF文書内にリンクを配置できます。この際に、文書の内部のリンクについては、HTMLと同様にその遷移先を“アンカー”（正式な用語では“destination name”という）で識別しています。ほとんどの場合、この“アンカー”の名は外部からは参照されず内部のリンクとアンカーの間で一貫していれば十分であるため、dvipdfmx（とXeLaTeX）では「アンカー名を連番の数字で付けなおす」という処理を行っています。しかし時には「2つのPDF文書の間でリンクを張りたい」なんて場合もあり、この際にdvipdfmxの既定の処理が行われると、リンクが正常に機能しなくなってしまいます。

`\preservepdfdestinations`命令はdvipdfmxの「アンカー名の付けなおし」の処理を抑止し、hyperref（等）によって生成されたアンカー名が保持されるようにします。

```tex
% アンカー名を保持する
\preservepdfdestinations
```

## まとめ

人生はもっと計画的に生きましょう（えっ:astonished:）