帳票を作る

請求書や納品書のような帳票を、テンプレートとデータから BDF として作れます。テンプレートは、文字のところにタグ({{名前}})を書いた Excel のブック、Word の文書、PowerPoint のプレゼンテーション、入力欄のある PDF、pdfme のテンプレート、帳票の行をタグつきで書いたテキストファイルです。データは JSON・YAML・CSV・Excel のファイルで、bdf fill がタグをデータに置き換え(または入力欄を埋め)、組版して .bdf を書き出します。Office のファイルは書き出しません。できた帳票は bdf pdf で PDF にできます。タグ付き PDF と PDF/A も選べます。

bdf fill -data order.yaml -data items=lines.csv invoice.xlsx invoice.bdf
bdf pdf invoice.bdf invoice.pdf
テンプレート 帳票の形 向いているもの
Excel(.xlsx) ブックが印刷するページ。行が増えればページが増える 表が中心の帳票、数式で計算する帳票、決まった行数の伝票
Word(.docx) 文書のページ。長くなった分は次のページへ流れる 文章と表の帳票、通知書、差し込みの手紙
PowerPoint(.pptx) スライド。図形は置いた場所から動かない 位置が決まった帳票、証書、ラベル、1 件 1 枚の資料
PDF フォーム(.pdf) PDF のページ。入力欄の場所に値が入る すでに PDF として配られている帳票。申請書、公的な様式
pdfme(.json) デザイナーで見えているページ。表はページをまたいで伸びる pdfme のデザイナーを使い、ブラウザでレイアウトした帳票
テキスト(.txt) 行と桁の格子に並べた文字。プリンタのテキストモードが印字するとおり ドットインパクトの連帳・複写伝票、レシート、ほかのシステムに渡す固定長のテキスト

タグの書き方とデータは、Office の 3 つの形式とテキストのテンプレートに共通です。同じデータを、形式の違うテンプレートに流し込めます。PDF フォームと pdfme のテンプレートにはタグの代わりにフィールドがあり、その名前で同じ形のデータを受け取ります。

インストールせずに試すなら、フォームのページにテンプレートをドロップしてください。タグを読んで入力フォームを作り、入力した値で穴埋めした帳票を表示して、PDF で保存できます。処理はすべてブラウザの中で行われ、ファイルはアップロードされません。

テンプレートを書く

普段どおりに帳票を作り、値を入れたいところにタグを書きます。まず Excel のブックで説明します。Word と PowerPoint は、同じタグが何を繰り返すかだけが違います(Word のテンプレート、PowerPoint のテンプレート)。

Excel では、用紙・余白・印刷範囲・印刷タイトル・改ページ・ヘッダーとフッターは、ブックのページ設定がそのまま使われます(Excel の印刷ビュー)。

タグ 意味
{{name}} 値。{{customer.name}} は値の中の値、{{.}} は項目そのもの
{{total | fmt:"#,##0"}} 表示形式を付けた値。書式は Excel の表示形式コード(yyyy年m月d日、ggge年、0.0% …)
{{#items}} … {{/items}} 区間。リストなら項目ごとに繰り返し、それ以外なら値が真のときだけ出す
{{^items}} … {{/items}} 逆の区間。リストが空、または値が偽のときだけ出す
{{%photo}} 画像。Excel ではセル(結合セルならその範囲)に、Word と PowerPoint では置いてある画像の枠に収める。{{%photo | fit:cover}} で枠を覆う、fit:stretch で引き伸ばす
{{%url | qr}}、{{%jan | barcode:jan}} 値の QR コード、バーコード(QR コードとバーコード)
{{%sign | signature}}、{{%seal | seal}} {{%photo}} と同じ画像。手書きのサインや印影のように、人が渡す方法が決まっているもの(サインと印影)

行を繰り返す

区間の開始と終了のタグを別々のセルに書くと、行の繰り返しになります。繰り返す行のセルからは、その項目の値が見えます。

行を増やす(開始と終了が同じ行): 項目ごとに行が 1 つ増え、下の行は押し下げられ、用紙に入らなければページが増えます。印刷タイトルの行は各ページで繰り返されます。

A B C D E
{{#items}}{{_index}} {{name}} {{qty}} {{price}}{{/items}} =C4*D4
合計 =SUM(E4:E4)

決まった行数に入れる(開始と終了が別の行): 開始のタグの行から終了のタグの行までが、項目を 1 つずつ入れる枠になります。行は増えず、項目のない行は罫線だけの空行として残ります。1 行目のタグと数式が、自分のタグを持たない残りの行にも使われます。項目が枠より多いとエラーになります。

A B C
{{#rows}}{{no}} {{name}} {{amount}}
(10 行目){{/rows}}

ページとして繰り返す(| pages): 開始から終了までの行のまとまりを項目ごとに複製し、それぞれを新しいページにします。10 行の伝票を 25 行分のデータで 3 枚にする、という帳票はこの形です。データは、ページごとの行と繰越をあらかじめ分けて渡します。

{ "pages": [
    { "rows": [ … 10 行 … ], "carry_in": 0,     "carry_out": 55000 },
    { "rows": [ … 10 行 … ], "carry_in": 55000, "carry_out": 210000 },
    { "rows": [ … 4 行 … ],  "carry_in": 210000, "carry_out": 300000 } ],
  "total": 300000 }

{{#pages | pages}} … {{/pages}} の中に {{#rows}} … {{/rows}} の枠を置きます。ページ番号は {{_page}} / {{_pages}}、最後のページだけに出す合計は {{#_last}}合計 {{total}}{{/_last}} と書けます。

{{#groups | rows}} と書けば、別の行にまたがるまとまりを、行を増やしながら繰り返します(グループの見出し・明細・小計)。区間は入れ子にできます。

開始と終了のタグを同じセルに書いた区間は、セルの中の文字を繰り返します({{#tags}}{{.}} {{/tags}})。同じセルでも | rows を付ければ行の繰り返しになるので、1 列だけの表でも行を増やせます({{#items | rows}}{{name}}{{/items}})。繰り返し方を書いた区間は、文字ではなく行(Word では段落、PowerPoint ではスライドなど)を繰り返す、という規則は 3 つの形式に共通です。逆の区間にも書けます({{^items | rows}}明細なし{{/items}} は、項目がないときだけその行を出します)。

区間の中で使える変数

変数 意味
_index、_count 何番目の項目か(1 から)、項目の数
_first、_last 最初・最後の項目か
_page、_pages `
_blank、_blank_first 枠の行で、項目のない行か、その最初の行か({{#_blank_first}}以下余白{{/_blank_first}})
_slide、_slides PowerPoint で、そのスライドの番号と、できあがったスライドの数

行に追随するもの

行が増えたり複製されたりすると、Excel で行を挿入したときと同じように、行を指しているものが付いてきます。結合セル、条件付き書式、リンク、印刷範囲と印刷タイトル、改ページ、図形、そして数式の参照です。複製された行の中の数式は自分の行(自分のページ)を指し、繰り返す行を含む範囲はすべての複製を含みます(=SUM(E4:E4) は全明細の合計になります)。

数式は穴埋めのあとで計算し直します。条件付き書式の評価器が知っている関数(四則、SUM、AVERAGE、COUNT、COUNTIF、IF、ROUND、文字列、日付 など)が対象で、それ以外の数式のセルは空にして警告を出します。

Excel の表見出しとセクションの改ページ

請求書では、Excel の「印刷タイトル」の「タイトル行」を表の見出しだけ (例: $15:$15)にします。帳票タイトルや宛名はこの範囲に含めません。 通常の印刷タイトルは後続の全ページに繰り返されますが、「数式 → 名前の管理」で 次の名前をシートのスコープに定義すると、BDF の改ページを調整できます。

名前 参照範囲の例 動作
_bdf.Print_TitleScope 'Invoice'!$A$15:$H$16 この表の明細が続くページだけに印刷タイトルを繰り返す。見出しと明細タグの行を含めると、項目数に合わせて範囲が伸びる。合計や備考だけのページには表見出しを付けない。
_bdf.Print_KeepTogether 'Invoice'!$F$18:$H$20,'Invoice'!$A$22:$H$25,'Invoice'!$A$27:$H$31 各範囲の行を同じページにまとめ、残りの高さに入らなければ次のページへ送る。合計・振込先・備考などを別々の範囲で指定する。

範囲はテンプレートの行の増減に追従します。繰り返す項目の中に置いた範囲は 各項目に適用されます。重なった範囲は一つのまとまりになり、隣接するだけの 範囲は別々に扱います。1 ページより高いまとまりは分割でき、手動の改ページは 優先されます。この名前は BDF の出力を制御するもので、Excel 自体の印刷プレビューは Excel の規則に従います。公開している Excel の請求書サンプルには両方を設定済みです。

Word のテンプレート

Word の文書では、本文・表のセル・テキストボックス・ヘッダーとフッターの文字にタグを書きます。穴埋めのあと文書を組み直すので、値が長くなれば行が増え、表の行が増えれば次のページへ流れます。表の見出し行(「タイトル行の繰り返し」)は、流れた先のページでも繰り返されます。帳票はページのビューだけになります。

区間が繰り返すものは、開始と終了のタグを両方含むいちばん小さいまとまりで決まります。

タグの位置 繰り返すもの
同じ段落 段落の中の文字
本文(または同じセル、同じテキストボックス)の別々の段落 開始の段落から終了の段落までの、段落と表
表の同じ行の別々のセル その行(項目ごとに行が増える)
表の別々の行 開始の行から終了の行までが、項目を 1 つずつ入れる枠(| rows を付ければ、行を増やしながら繰り返す)

PowerPoint のテンプレート

PowerPoint では、図形・テキストボックス・表のセルの文字にタグを書きます。スライドは固定のページで、図形は置いた場所から動きません。

タグの位置 繰り返すもの
同じ段落 段落の中の文字
同じ図形(または同じセル)の別々の段落 開始の段落から終了の段落まで
表の同じ行の別々のセル その行(項目ごとに行が増える)
表の別々の行 開始の行から終了の行までが、項目を 1 つずつ入れる枠(| rows で行を増やす繰り返し)
同じスライドの別々の図形 そのスライド(項目ごとに 1 枚)
別々のスライド 開始のスライドから終了のスライドまで

PDF フォーム

入力欄のある PDF(AcroForm。Acrobat や LibreOffice、多くのフォーム作成ツールが作るもの)は、そのままテンプレートになります。入力欄の名前がデータの名前です。bdf fill は入力欄の場所に値を描き、PDF のページを BDF の文書として書き出します。できた帳票に入力欄は残りません。

bdf template schema -json-schema application.pdf   # 入力欄を、データの JSON Schema として
bdf fill -data applicant.json application.pdf application.bdf
bdf pdf application.bdf filled.pdf
入力欄 データ
テキスト 文字列か数値。複数行の欄は欄の幅で折り返し、マス目の欄(comb)は 1 文字ずつマスに入れ、大きさが自動の欄は収まる大きさにする
チェックボックス true か false
ラジオボタン 選ぶボタンの値
リスト、ドロップダウン 選択肢の値。欄には、その選択肢の表示名が出る
署名 画像(手書きのサインなど)。欄の箱の中央に、全体が収まるように描く(サインと印影)

pdfme のテンプレート

pdfme は、ブラウザで動くデザイナーを持つオープンソースの PDF 生成ライブラリです。そのデザイナーが保存するテンプレート(JSON のファイル。土台の PDF か白紙のページと、ミリ単位で場所を決めたフィールド)も、そのままテンプレートになります。pdfme の生成器と同じ規則で埋めます。

bdf fill -data invoice.json template.json invoice.bdf
bdf template compile template.json invoice.bdft   # デザイナーで入れてあった内容のページになる
pdfme のフィールド データ
text、select 文字列か数値(select は選択肢の 1 つ)
multiVariableText 変数のオブジェクト。"customer": {"company": "…", "person": "…"}
date、time、dateTime 日付(2026-10-14、2026/10/14)、時刻(09:30)、またはその両方。フィールドの書式で描く(月や曜日の名前は英語と日本語)
checkbox、radioGroup、circleMark true か false
image、signature、svg ファイルのパスか data: URL(svg は SVG そのものでもよい)
qrcode、ean13、ean8、code39、code128、nw7、itf14、upca コードの内容
table 行の配列。行は、列の名前をキーにしたオブジェクトか、セルの配列
list 文字列の配列(先頭にタブを置くと 1 段深くなる)

テキストのテンプレート

テキストファイル(UTF-8)は、ドットインパクトプリンタが連続用紙や複写伝票に、レシートプリンタがロール紙に印字する帳票のテンプレートになります。行と桁の格子に文字を並べた帳票です。エディタで見えているものがそのまま帳票で、ファイルの 1 行がページの 1 行、1 文字が 1 桁、全角の文字(漢字、かな)は 2 桁です。ほかのテンプレートと同じタグとデータで穴埋めします。

---
cpi: 10                  # 1 インチあたりの桁数
lpi: 6                   # 1 インチあたりの行数
columns: 80              # 用紙の幅(桁)
lines: 33                # ページの長さ(行。0 はロール紙で、帳票の長さだけ伸びる)
margin: {left: 2, top: 1}
skip: 2                  # ミシン目をまたいで空ける行数
---
                  {{#_big}}納品書{{/_big}}                {{date | fmt:"yyyy年m月d日"}}
{{#preprinted}}得意先{{/preprinted}} {{customer | width:30}}{{#preprinted}}御中{{/preprinted}}  No. {{no | right:8}}
{{#preprinted}}
┌──────────────────────┬──────┬────────────┐
│ 品名                 │ 数量 │ 金額       │
{{/preprinted}}
{{#rows}}
│ {{name | width:20 | cut}} │ {{qty | right:4}} │ {{amount | fmt:"#,##0" | right:10}} │
│                      │      │            │
│                      │      │            │
{{/rows}}
bdf fill -data order.json slip.txt slip.bdf    # 文書として: 表示、印刷、PDF に
bdf fill -data order.json slip.txt slip.txt    # プレーンテキストとして: 行を並べ、ページは改ページ(FF)で区切る
bdf template compile -sample order.json slip.txt slip.bdft

前書き(--- の行で囲んだ YAML。なくてもよい)が格子を決めます。前書きがなければ、10 CPI・6 LPI の 80 桁 × 66 行(8 × 11 インチの連続用紙)です。

キー 意味
cpi、lpi 1 インチあたりの桁数と行数。10・12・15・17.1・20 CPI、6・8 LPI(ESC/P のピッチ。ほかの値は警告)
columns、lines 用紙の大きさを桁と行で。余白を含む。lines: 0 はロール紙で、ページはその行の数だけの長さになる(レシート)
margin: {left, top} 各行の前に空ける桁数と、先頭の行の上に空ける行数
skip 各ページの下に空ける行数(ミシン目スキップ)
title 帳票の先頭の行を、各ページの上に繰り返す(一覧の見出し)
font ページを描く等幅フォント。ファミリー名(BIZ UDGothic)か、テンプレートの隣のフォントファイル(fonts/slip.ttf。ディレクトリは -files で変えられる)
ambiguous 東アジアの文字幅が「あいまい」な文字(罫線素片、○、※、ギリシャ文字)の桁数。narrow(1。既定。多くのエディタの表示と同じ)か wide(2)

値は、その文字の桁数だけ場所を取り、後ろの文字を押します。桁数を書いた値はちょうどその桁数を取り、全角は 2 桁と数えます。{{name | width:20}} は 20 桁に左揃え、{{no | right:8}} は右揃え、{{title | center:30}} は中央揃えです。値が桁数を超えると、切らずに書いて警告を出します。| cut は切り、| wrap は残りを下の行の同じ桁に続けます({{address | width:30 | wrap}})。値の中の改行も、同じように次の行へ続けます。

タグだけの行。 行をまたぐ区間のタグだけの行は、帳票の行を占めません。ファイルの中の改ページ(FF)はページを改めます。

区間は、ファイルの行をブックの行とみなして、Excel と同じに繰り返します(行を繰り返す)。1 行の中の区間は文字を繰り返し({{#tags}}{{.}} {{/tags}})、行をまたぐ区間はタグの間の行に 1 行 1 項目ずつ入れます(枠。項目のない行は値なしでそのまま残り、タグのない枠の行は最初の行と同じになります)。{{#items | rows}} は項目ごとに行を繰り返し、ページが埋まると改ページして、title の行を各ページの上に置きます。{{#pages | pages}} は項目ごとに別のページで繰り返します。| rows の区間のない帳票はページに収まらなければなりません(折り返した値は下の行を押し下げ、ページの終わりを越えるとエラーです)。区間の変数はほかのテンプレートと同じです。

データを引かない区間が 3 つあります。

区間 意味
{{#preprinted}} … {{/preprinted}} 用紙に印刷済みの罫線と項目名。役割 background のレイヤーに描くので、その用紙に刷るときは抜けます(プリンタの設定の SkipRoles)。行をまたいでも、1 行の中でも書ける
{{#_wide}} … {{/_wide}} 倍幅の文字。半角は 2 桁、全角は 4 桁
{{#_tall}} … {{/_tall}}、{{#_big}} … {{/_big}} 倍高の文字と、倍角(幅と高さが倍)の文字。その行はページの 2 行を占め、文字は下の行のベースラインに立つ

帳票は、用紙の大きさ(columns / cpi × lines / lpi インチ)のページの fixed View です。文字は等幅フォントでそれぞれの桁に描きます。BIZ UDゴシック(Google Fonts、SIL Open Font License)、次に IPAゴシック、Noto Sans Mono CJK JP、システムの等幅フォントの順に探し、どのフォントでも文字は格子からずれません。検索・コピー・タグ付き PDF のために、各行は段落、rows と枠の区間の行は表になります。

印字像。 文書は、格子と各行の文字を専用の Part(t: "text"、仕様 §4。JSON の形は Go の form/textpart パッケージが説明しています)にも持ちます。どの範囲がプレ印刷の用紙で、どの範囲が倍角かも入ります。ビューアはこの Part を読みません。プリンタのテキストモード(ドットインパクトの ESC/P、レシートプリンタの ESC/POS)はこれから印字し、bdf fill … out.txt もこれを書きます。

-param 意味
encoding=shift_jis テキストの文字コード。utf-8(既定)、shift_jis(Windows-31J)、euc-jp、iso-2022-jp、ほか WHATWG Encoding Standard の名前。その文字コードにない文字は 〓 にして警告を出す
newline=crlf 行の終わりを LF の代わりに CR LF にする
paper=preprinted プレ印刷の用紙の範囲を空白で書く

印刷。 bdf print は、ESC/P のドットインパクトプリンタにはテキストモードで送ります。ピッチ・行送り・用紙長・ミシン目スキップはテンプレートのもので、文字はプリンタのフォントで(漢字は漢字モード)、-skip background でプレ印刷の用紙の範囲を刷りません。ESC/POS のレシートプリンタは -print-mode text で同じように刷ります。

bdf print -printer 'socket://192.168.0.20:9100?profile=vp-f2000' -skip background slip.bdf
bdf print -printer 'serial:///dev/ttyUSB0?profile=tm-t88' -print-mode text receipt.bdf

ambiguous: narrow のテンプレートの 1 桁の文字(罫線素片、○、※)を、ESC/P は半角の漢字で刷ります。レシートプリンタにはそれが無いので、罫線素片と × は 1 バイトの文字の表から刷り、ほかは警告を出して ? にします。○ や ※ を使うレシートは ambiguous: wide と書いてください。ESC/P には漢字を縦だけ 2 倍にする命令が無いので、_tall の漢字は普通の大きさで刷り、警告を出します。ESC/P は 10・12・15・17.1・20 CPI(漢字は 10〜15)、ESC/POS は 1 桁が 12 ドット以上になるピッチ(180 dpi と 203 dpi で 15 CPI まで)を刷れます。そう刷れない帳票は、警告を出してドットで刷ります(-print-mode text のときは誤り)。

テキストのテンプレートに画像、QR コード、バーコードは書けません(プリンタのテキストモードは文字を印字するため)。私用領域の文字(外字)と絵文字は、プリンタが持っていないので警告します。

QR コードとバーコード

画像のタグに qr か barcode:種類 を付けると、値を符号化したコードを画像の代わりに描きます。置く場所は画像と同じです。Excel ではタグを書いたセル(結合セルならその範囲)、Word と PowerPoint では代替テキストにタグを書いた画像の枠です。

タグ 描くもの
{{%url | qr}} QR コード(モデル 2、バージョン 1〜40)。誤り訂正レベルは M。qr:L、qr:Q、qr:H で変える
{{%jan | barcode:jan}} JAN / EAN-13。12 桁の値にはチェックデジットを付け、13 桁の値は確かめる。barcode:ean13 も同じ
barcode:ean8、barcode:upca JAN / EAN-8(7 桁か 8 桁)、UPC-A(11 桁か 12 桁)
barcode:code39 Code 39。数字、英大文字、空白、- . $ / + %。前後の * は自動で付く
barcode:code128 Code 128。ASCII の文字。コードセット A・B・C は自動で選ぶ
barcode:gs1-128 GS1-128。値は (01)04901234567894(10)ABC のように、AI を括弧で書く
barcode:itf、barcode:itf14 ITF(数字。奇数桁なら先頭に 0 を足す)、ITF-14(13 桁ならチェックデジットを付ける)
barcode:nw7 NW-7(Codabar)。数字と - $ : / . +。スタートとストップ(A〜D)を値に書かなければ A で挟む

フォームを使わず、同じ描画を直接生成することもできます。

symbol, err := barcode.Encode("jan", "490123456789", nil) // チェックデジットを補い 4901234567894 に
// err を確認してから、バーと数字を一緒に描きます。
drawing := symbol.Object(113, 36)

バーだけ描く場合は &barcode.Options{NoText: true} を渡します。Symbol.At と Symbol.Rects は、数字の描画とは独立して符号化されたモジュールだけを返します。

PDF にする

bdf pdf は、BDF の文書を PDF に書き出します。帳票に限らず、どの文書でも使えます。

bdf pdf invoice.bdf invoice.pdf
bdf pdf -skip background -skip master slip.bdf slip.pdf   # 印刷済みの用紙に重ねて刷る
bdf pdf -tagged report.bdf report.pdf                      # タグ付き PDF
bdf pdf -pdfa 2a invoice.bdf invoice.pdf                   # 保存用の PDF/A

タグ付き PDF と PDF/A

タグ付き PDF(-tagged)は、ページの見た目とは別に、文書の構造を持つ PDF です。どの文字が見出しで、どれが段落、箇条書きの項目、表のセルなのか、どの順に読むのか、図は何を表しているのかが入ります。スクリーンリーダーはこの構造をたどって読み上げ、PDF から文字を取り出すツールは段落や表を崩さずに取り出せます。

PDF/A(-pdfa)は、長期保存のための PDF です。10 年後に開いても同じに見えるように、開くマシンに頼るものを一切持ちません。

レベル 約束すること
2b どこで開いても同じに見える。すべてのフォントを埋め込み、色は PDF に入れた出力インテント(sRGB)で決まり、メタデータが規格を名乗る
2u 加えて、文字が Unicode に対応する。検索とコピーで正しい文字が得られる
2a 加えて、タグ付きである(-tagged を兼ねる)
3b、3u、3a 規格の第 3 部で、同じ内容

データ

データは JSON の値でできた 1 つのオブジェクトです。-data を繰り返して組み立てます。

書き方 読み方
-data order.json、-data order.yaml オブジェクト。後のファイルが同じ名前の値を置き換える
-data items=lines.csv CSV・TSV を、1 行目を名前にしたオブジェクトのリストとして、その名前に置く。文字コードと区切りは自動で判定(Shift_JIS も読む)
-data book.xlsx、-data items=book.xlsx ブックのシートごとのリスト(シート名が名前)。名前を付けた 1 シートのブックはそのリスト
-data customer.address=addr.json JSON・YAML の値を、その名前に置く

CSV の値は、JSON の数値と同じ書き方のものだけが数値になります(007 や 1,234 は文字列のまま)。true と false は真偽値、空は値なしです。画像はファイルのパス(-files のディレクトリ、既定ではテンプレートのディレクトリから)か data: URL で渡します。パスはそのディレクトリの中にとどまります。.. や外へ出るリンクはたどりません。

データにない名前のタグは空にして警告を出します。-strict を付けるとエラーにします。

レコードごとに 1 つずつ帳票を作るには -each を使い、出力のパスにタグを書きます。

bdf fill -each orders.csv -data items=lines.csv invoice.xlsx 'out/{{customer}}-{{no}}.bdf'

1 つの文書に全員分をまとめるなら、テンプレートの側で {{#orders | pages}} を使います。

コンパイル済みテンプレート(.bdft)

bdf template compile はテンプレートを検査し(タグの閉じ忘れや、行をまたぐ区間の書き間違いを、セルの番地や段落・図形の場所つきで報告します)、コンパイル済みテンプレートを書き出します。中身は BDF の文書で、サンプルデータで穴埋めしたページ(サンプルがなければタグのままのページ)を見せ、テンプレートそのものと、タグが引く名前の一覧を持ちます。ビューアやサムネイルでそのまま開け、bdf fill にテンプレートの代わりに渡せます。

bdf template compile -sample sample.yaml invoice.xlsx invoice.bdft
bdf template schema invoice.bdft        # タグが引く名前を JSON で
bdf fill -data order.yaml invoice.bdft out.bdf

一部だけ埋めた帳票(.bdff)

帳票を何人かで埋めることがあります。契約書なら、送る側が自分の欄を埋めて署名し、相手が残りを埋めます。-open で後に残す名前を指定すると、bdf fill は残りを空けた帳票(.bdff)を書き出します。

bdf fill -data mine.yaml -open party_b contract.bdft contract.bdff   # 甲の分
bdf template schema -json-schema contract.bdff                       # 残りの欄: party_b
bdf fill -data theirs.json contract.bdff contract.bdf                # 乙が残りを埋めて完成

値に署名する

-sign-key と -sign-cert は、その穴埋めで渡したものに署名します。署名するのは、そのときの帳票の値・空けた名前・テンプレート(の SHA-256)で、ページではありません。ページは他の人が埋めると変わるからです。.bdff は署名を持ち、そこから完成させた帳票は、値の記録とすべての署名を持ちます(型 fill の Part、spec §4.5)。

bdf fill -data mine.yaml -open party_b -sign-key alice.key -sign-cert alice.pem -sign-role author contract.bdft contract.bdff
bdf fill -data theirs.json -sign-key bob.key -sign-cert bob.pem contract.bdff contract.bdf
bdf sign -key witness.key -cert witness.pem -role witness contract.bdf    # ページと記録に
bdf verify -roots ca.pem contract.bdf

bdf verify は値の署名ごとに、署名した値がすべて帳票の値と同じか、署名した人が埋めた名前を帳票が空けていないかを確かめます。完成させる前に .bdff の値を書き換えると、その値を渡した人の署名が成り立たなくなります。ページへの署名は bdf sign です(sign, verify)。その署名は記録も覆います。-open なしで署名すると、帳票の値をすべて署名します。

フォームのページでは、「Leave for another person」で名前にチェックを付けると、文書を .bdff として保存できます。そのページで .bdff を開くと、残した名前の欄だけが出ます。

サインと印影

{{%sign | signature}} と {{%seal | seal}} は画像で、{{%photo}} と同じように埋めて描きます(| fit: も使えます)。違うのは人がどうやって渡すかで、スキーマの x-bdf.input に入ります。

input フォームのページ
signature ペン・指・マウスで書くパッド。書いた線は SVG の画像(data: URL)になり、PDF でどれだけ拡大してもぼけません
seal 印影の画像を選ぶと、白い部分を抜きます。文字の上に重ねて押せます

PDF フォームの署名欄(/FT /Sig)と pdfme の signature も、同じく signature の画像の欄になります。

手書きのサインは、サインの絵であって電子署名ではありません。誰が書いたかも、その後に文書が書き換えられていないことも証明しません。

データの JSON Schema と入力フォーム

テンプレートが求めるデータの形は、JSON Schema として取り出せます。入力フォームを自動で作るライブラリや、データの検証にそのまま渡せます。フォームのページの入力欄も、このスキーマから作っています。

bdf template schema -json-schema invoice.xlsx invoice.schema.json
bdf template schema -json-schema -sample sample.yaml invoice.xlsx   # サンプルで型と場所を確かめる

タグは値の型を書かないので、スキーマはタグから推し量ったものです。

テンプレートの書き方 スキーマ
{{name}} 文字列か数値("type": ["string", "number"])
{{total | fmt:"#,##0"}} 数値。日付の表示形式(yyyy/mm/dd)なら "format": "date" の文字列
{{customer.name}} オブジェクト customer のプロパティ name
中に名前か {{.}} がある区間、| rows・| pages の区間 配列。項目はオブジェクトか値。枠の区間(slots)は maxItems が枠の数
それ以外の区間({{#paid}}■{{/paid}}) 真偽値
{{%photo}} 文字列(ファイルのパスか data: URL)。| signature・| seal は x-bdf に "input" が付く
{{%url | qr}}、{{%jan | barcode:jan}} 文字列(コードの内容)

Go から使う

data, err := form.LoadData(
	form.Source{FileName: "order.yaml", Data: order},
	form.Source{Name: "items", FileName: "lines.csv", Data: lines})
res, err := form.Fill(template, size, &form.Options{Data: data})
err = res.Doc.WriteSingle(out)

form.Fill は、テンプレートの形式を中身から判定します(Office のファイル、PDF フォーム、pdfme のテンプレート、テキストのテンプレート、コンパイル済みテンプレート、一部だけ埋めた帳票)。Options.Open を渡すと一部だけ埋めた帳票を作り、res.Partial がそれを記述します。form.Fields はタグが引く名前を、form.SchemaOf はデータの JSON Schema を、form.Compile はコンパイル済みテンプレートを返します。形式が決まっていれば xlsx.Fill、docx.Fill、pptx.Fill、textform.Fill を直接呼べます。textpart.Read は文書からテキストの帳票の印字像を読み、textform.Plain はそれをプレーンテキストにします。PDF は pdfbdf.Write で書き出します。

res, err := pdfbdf.Write(out, doc, &pdfbdf.Options{})                          // PDF
res, err = pdfbdf.Write(out, doc, &pdfbdf.Options{Tagged: true, PDFA: "2a"}) // タグ付きの PDF/A-2a

知っておくこと