SATySFiで年賀状宛名印刷する話

:::note info
これは「[SATySFi Advent Caleandar 2022](https://adventar.org/calendars/7515)」の12日目の記事です。
:::

今年も暮れが押し迫ってきて、新年を迎える準備に忙しい時候になりました。というわけで「**年賀状の宛名印刷**のためのSATySFi文書クラス」という**ネタ**をつくってみました:smiley:

## ネタ注意の話

年賀状の宛名印刷というと何やら実用的な話にも聞こえますが、この記事は基本的に**ネタ話**です。

葉書の宛名は**縦書き**するのが普通ですが、実は現状のSATySFiは**まだ縦組をサポートしていません**。縦組のサポートがないところで無理やり縦組をしようとしてもおおよそマトモな出力は得られません。

とはいっても「葉書の宛名程度であればマトモな出力なんて不要で、字が読めさえすれば十分だ:neutral_face:」という考えもあるでしょう。そういう人にとっては、もしかしたら実用性もチョットあるのかもしれません。

## 使用例を紹介する話

以下の場所から年賀状宛名印刷のための**​「addrite パッケージ」​**を入手できます。ファイル`addrite.satyh`だけ用意すれば十分です。

* [SATySFI: 年賀状宛名印刷用文書クラス][gist]

:::note info
`addrite`パッケージはライブラリルートにインストールして使うこともできますが、パッケージの性質を考えて（**ネタ**なので）ここではパッケージファイルを**文書ファイルと同じディレクトリに置く**ことにします。このため文書ソース中では`addrite`は`@import`で読み込んでいます。
:::

`addrite`を使った文書のソースコードの例を挙げます。

```text:addrite-sample.saty
@import: addrite
open Addrite
in

document '<
  +address-from(`1234567`){
    \tate((3.2cm,8.0cm))[top](10pt)(`東京都羅轍区照府(82)-(3)-(14)`);
    \tate((2.7cm,3.0cm))[bottom](10pt)(`照府ヒルズ(1519)号室`);
    \tate((1.5cm,7.4cm))[top; spread 4.4cm](18pt)(`独 歌  紡 志`);
  }
> '<
  +address-to(`4703389`){
    \tate((9.0cm,12.2cm))[top](15pt)(`愛知県南セントレア市北カエリア区`);
    \tate((8.2cm,3.0cm))[bottom](15pt)(`西アヴィエリア(32)-(512)-(8)`);
    \tate((6.0cm,11.4cm))[top; spread 8.4cm](32pt)(`幸 主  扶 愛  様`);
  }
>
```

この文書ソースファイル`addrite-sample.saty`とパッケージファイル`addrite.satyh`を**同じディレクトリ**に置いて以下のコマンドを実行します。 

```bash
satysfi addrite-sample.saty
```

すると以下のような出力が得られます。

![addrite-sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/ec329584-8a89-e8ab-a870-803421cf7755.png)

## 使い方を説明する話

:::note info
ここでは`addrite`の機能の一部を大まかに紹介します。仕様の詳細については[説明書][doc]を参照してください。
:::

### 全体構成

```text:addrite-sample.saty
@import: addrite
open Addrite
in

document ?:[
  «設定項目»; ……
] '<
  +address-from(`«差出人郵便番号»`){
    «差出人住所内容»
  }
> '<
  +address-to(`«宛先人1郵便番号»`){
    «宛先人1住所内容»
  }
  +address-to(`«宛先人1郵便番号»`){
    «宛先人2住所内容»
  }
  ……(任意件数記述可能)
>
```

:::note info
`addrite`パッケージの機能はAddriteというモジュールの形で提供されます。通常はAddriteをopenすることが想定されています。
:::

`document`函数のオプション引数（`?:[«設定項目»;…]`）には[**設定項目**][doc-config]のリストを指定します。例えば、郵便番号出力のフォントを`lmmono`（Latin Modern Mono）に変更したい場合は以下のように書きます。

```text
document ?:[postal-code-font (`lmmono`, 1.0, 0.0)] ……
```

また、上級者用の機能ですが、`update-context`で全体出力のテキスト処理文脈に比較的自由に更新を加えることができます。例えば「和文のフォントを`ipaexg`（IPAゴシック）に変更する」という設定は以下のコード[^ja-script]で実現できます。

[^ja-script]: `HanIdeographic`（漢字）と`Kana`（仮名）の両方の用字系についてフォントを設定する必要があります。

```text
document ?:[
  update-context (set-font HanIdeographic (`ipaexg`, 1.0, 0.0));
  update-context (set-font Kana (`ipaexg`, 1.0, 0.0));
] ……
```

`document`の最初の必須引数には差出人の情報を記述したブロックテキストを指定します。このブロックテキストは高々1個の`+address-from`コマンドのみを含められます。`+address-from`コマンドで記述した差出人の情報は**全ての**ページ（宛名面印刷）に出力されます。

`document`の2番目の必須引数には宛先人の情報を記述したブロックテキストを指定します。このブロックテキストは0個以上の`+address-to`コマンドのみを含められます。1つの`+address-to`コマンドが1件の宛名人の情報を表し、個別のページ（宛名面印刷）に出力されます。

`+address-from`および`+address-to`コマンドの第1引数には郵便番号を文字列で指定します。この文字列は`1234567`のように7桁の数字からなる必要があります。ただし`123-4567`のようにハイフンを含めてもかまいません（出力は変わりません）。もし空欄にしたい場合は`123____`のように`_`を書きます。

### テキスト配置コマンド

`+address-from`および`+address-to`コマンドの第2引数は住所を記述するためのインラインブロックで、ここには**テキスト配置コマンド**を記述します。テキスト配置コマンドには以下のものがあります[^segments]。

[^segments]: 実は縦組のテキスト配置コマンドにはもう1つ、`\tate-segments`という（隠し？）コマンドもあったりします。

```text
% 縦組用
\tate(«出力位置»)[«オプション»;…](«フォントサイズ»)(`«文字列»`);
% 横組用
\yoko(«出力位置»)[«オプション»;…](«フォントサイズ»)(`«文字列»`);
\yoko-text(«出力位置»)[«オプション»;…](«フォントサイズ»){«テキスト»}
```

出力位置については、例えば

```
\tate((6cm,5cm))[top](10pt)(`文字列`);
```

であれば、「文字列」を縦組で出力したもの（矩形領域）をその上端が (6cm, 5cm) の位置に来るように出力されます[^anchor]。ここで座標は「左下を原点としてx座標が右向き、y座標が上向き」と定められています。

[^anchor]: つまり`top`は**アンカー**の位置を示します。指定座標からみた「文字のある方向」は正反対の方向（`top`なら下、`left`なら右）になることに注意してください。

テキスト配置コマンドの第2引数には[**オプション**][doc-option]のリストを指定します（この引数自体はオプション引数ではないことに注意）。オプションに指定できる値には以下のもの（抜粋）があります。

* `center`(中央)、`top`(上)、`bottom`(下)、`left`(左)、`right`(右) などのアンカー位置を指定するためのもの。なお、アンカー位置の既定値は`center`。
* `spread «長さ»`で、全体が指定の長さになるように**均等割付**することを指示する。均等割付は入力文字列中の「ASCII空白文字で入る空き[^std-space]」を伸縮することで実現される。例えば`独␣歌␣␣紡␣志`の入力では“歌”と“紡”の間の空きはその他の文字間の空きの2倍になる。\
※`spread`は縦組のテキスト配置コマンド（`\tate`）でのみ使用可能。

[^std-space]: `spread`を指定しない場合は、「ASCII空白文字で入る空き」の量は半角になります。ただしこの量は設定項目の`space-size`で変更できます。

縦組の[^yoko-text]テキスト配置コマンド（`\tate`）の入力文字列中では`(` `)`の文字が特別な意味をもち、`(`と`)`で囲まれた部分が縦中横で出力されます。その他の部分の文字は和文・欧文問わず正立の向きで出力されます。

[^yoko-text]: `\yoko`コマンドの入力文字列は単純にSATySFiの仕様に従って（`embed-string`により）インラインテキストに変換された後に出力します。`\yoko-text`の入力のテキストはSATySFiの仕様に従って組まれます。

## まとめ

やっぱり、早くSATySFIの縦組機能が実現されてほしいですね！:smiley:

[doc]: https://gist.github.com/zr-tex8r/aaa33b8a32c3baeb08dcf92e22a6fd38#file-00addrite-md
[doc-config]: https://gist.github.com/zr-tex8r/aaa33b8a32c3baeb08dcf92e22a6fd38#%E8%A8%AD%E5%AE%9A%E9%A0%85%E7%9B%AE
[doc-option]: https://gist.github.com/zr-tex8r/aaa33b8a32c3baeb08dcf92e22a6fd38#%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E9%85%8D%E7%BD%AE%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3
[gist]: https://gist.github.com/zr-tex8r/aaa33b8a32c3baeb08dcf92e22a6fd38