あと少しすればもう年末。年賀状を書かなければならない時期が来る。住所録から LaTeX を用いてハガキ宛名印刷用 PDF を生成するツールを作ってみた。これは昔 UNIX 系の雑誌にあった記事の工夫なので,ネットで探せば同様のツールが見つかるかも知れないが,私自身の好みでレイアウトをカスタマイズできるよう,スクラッチから(すべてを一から)自作してみた。mkpostaddr-
処理方式は次のとおり。住所録 CSV ファイル(address.csv),

住所録 CSV ファイルは,項目をカンマ区切りで記述した,いわゆる CSV ファイルである。このツールでは,1:宛名-姓, 2:宛名-名, 3:宛先郵便番号, 4:宛先住所(番地まで), 5:宛先住所(ビル,マンション情報), 6:会社名, 7:部署名, 8:宛名連名-姓, 9:宛名連名-名 の 9 項目からなるデータを前提としている。5 〜 9 は無ければ空データもしくは空白としておいてよいが,カンマは必ず全部で 8 必要である。Microsoft Excel などで住所録を作成し,区切り文字カンマ,文字コード UTF-8 指定で CSV 出力すればよい。このデータはハガキ差込フォーム・ファイルで記述された所定の変数位置に埋め込まれ,ハガキ宛名 LaTeX コードとなる。郵便番号の出力位置と差出人情報をハガキレイアウト定義ファイルに書いておく。郵便番号の出力位置については,日本郵便社お年玉年賀ハガキ向けにすでに調整してある。掲載ファイルにはサンプルが記述されているが,差出人は変更するか,不必要なら空にしておく。
住所に英文字以外の外国語,たとえばロシア語を使いたい場合は,{\selectlanguage
少し長大になるが,各ファイル内容を掲載しておく。
住所録 CSV ファイル(サンプル)
あくまでサンプル。必ず,自分用に CSV 形式で作成してください。
# -*- coding: utf-8; mode: text; -*-
# 住所録CSVファイル(サンプル)
# 1:宛名姓,2:宛名名,3:郵便番号,4:住所1,5:住所2(建物),
# 6:会社名,7:部署名,8:宛名(連名)姓,9:宛名(連名)名
\CID{13706}田,太郎,1020082,東京都千代田区一番町一--二--三,一番ビルヂング地下一階,株式会社 ヨシダ商事,営業部,,花子
鈴木,花子,1020072,東京都千代田区飯田橋四--五--六,,,,,
高橋,一郎,2100808,神奈川県川崎市川崎区旭町一--二三--四,大日本マンション一〇一号,,,,\hspace*{.5zh}桜\hspace*{.5zh}
ハガキ差込フォーム・ファイル
LaTeX コードにおいて住所録の数だけ繰返し出力される宛名印字頁整形用の雛形である。:数字: の部分が,住所録 CSV ファイルの情報で書換えられる。印字の位置,文字の大きさなど,気に入らなければ適宜修正ください。基本的には弄る必要はない。
% -*- coding: utf-8; mode: latex; -*-
% ハガキ差込フォーム・ファイル(TeX form 原稿)
% 2011 (c) isao yasuda.
\begin{picture}(100,148)(3,3)
%% 宛先郵便番号
\Huge
\put(\cntTOX,\cntTOY){\makebox[6mm][c]{:1:}}%第1桁
\advance\cntTOX by \cntTOW
\put(\cntTOX,\cntTOY){\makebox[6mm][c]{:2:}}%第2桁
\advance\cntTOX by \cntTOW
\put(\cntTOX,\cntTOY){\makebox[6mm][c]{:3:}}%第3桁
\put(\cntTTX,\cntTTY){\makebox[6mm][c]{:4:}}%第4桁
\advance\cntTTX by \cntTTW
\put(\cntTTX,\cntTTY){\makebox[6mm][c]{:5:}}%第5桁
\advance\cntTTX by \cntTTW
\put(\cntTTX,\cntTTY){\makebox[6mm][c]{:6:}}%第6桁
\advance\cntTTX by \cntTTW
\put(\cntTTX,\cntTTY){\makebox[6mm][c]{:7:}}%第7桁
%% 住所
\put(70,30){%
\makebox(20,94)[rt]{%
%\framebox(20,94)[rt]{%
\begin{minipage}<t>[t]{94mm}
\Large
:8:\\%住所1
\vspace*{1mm}%
\hspace*{5mm}%
:9:%住所2
\end{minipage}
}%
}%
%% 会社名・部書名・連名
\put(45,30){%
\makebox(30,88)[rt]{%
%\framebox(30,88)[rt]{%
\begin{minipage}<t>[t]{88mm}
\hspace*{3mm}%
\vspace*{-7mm}%
{\large :10:\\}%会社名
\hspace*{7mm}%
\vspace*{-3mm}%
{\large :11:\\}%部署名
\vspace*{-3mm}%
\def\lastname{:00:}%
\settowidth{\namelen}{\lastname}\addtolength{\namelen}{1zw}%
\makebox[\namelen][l]{\lastname}:01:~様\\%宛名
%\hspace*{20mm}%
\makebox[\namelen][l]{:12:}%
:13:%連名
\end{minipage}
}%
}%
%% 差出人住所・氏名
\put(10,32){%
\makebox(30,58)[rt]{%
%\framebox(30,58)[rt]{%
\small
\begin{minipage}<t>[t]{58mm}
{\large :20:}\par%住所1
\vspace*{3mm}%
{\Large
\hspace*{5mm}%
\makebox[3.5zw][l]{:21:}\qquad :22:\\[2pt]%差出人姓名
\hspace*{5mm}%
\makebox[3.5zw][l]{:23:}\qquad :24:}\par%連名姓名
\vspace*{3mm}%
\hfill{\large :25:}%
\end{minipage}
}%
}%
%%% 差出人郵便番号
\large
\put(\cntFOX,\cntFOY){\makebox[4mm][c]{:30:}}%第1桁
\advance\cntFOX by \cntFOW
\put(\cntFOX,\cntFOY){\makebox[4mm][c]{:31:}}%第2桁
\advance\cntFOX by \cntFOW
\put(\cntFOX,\cntFOY){\makebox[4mm][c]{:32:}}%第3桁
\put(\cntFTX,\cntFTY){\makebox[4mm][c]{:33:}}%第4桁
\advance\cntFTX by \cntFTW
\put(\cntFTX,\cntFTY){\makebox[4mm][c]{:34:}}%第5桁
\advance\cntFTX by \cntFTW
\put(\cntFTX,\cntFTY){\makebox[4mm][c]{:35:}}%第6桁
\advance\cntFTX by \cntFTW
\put(\cntFTX,\cntFTY){\makebox[4mm][c]{:36:}}%第7桁
\end{picture}
ハガキレイアウト定義ファイル(サンプル)
Perl プログラムの変数定義の形式で記述する。差出人情報は必ず修正しなければならない。宛名面に差出人情報を印字したくない場合は,ごっそり削除すればよい。郵便番号を出力する位置は,ミリ単位,整数で指定しないといけない。すでに日本郵便社お年玉年賀ハガキ向けに私が調整してあるので,修正する必要はないと思う。
# -*- coding: utf-8; mode: cperl -*- # ハガキレイアウト定義ファイル # 2011 (c) isao yasuda. # 宛先郵便番号 $POSTNUMT1POSX = 46; # 1桁目X位置 $POSTNUMT1POSY = 131; # 1-3桁目Y位置 $POSTNUMT1WIDTH = 7; # 1-3桁目送り幅 $POSTNUMT2POSX = 67; # 4桁目X位置 $POSTNUMT2POSY = 131; # 4-7桁目Y位置 $POSTNUMT2WIDTH = 7; # 4-7桁目送り幅 # 差出人郵便番号 $POSTNUMF1POSX = 10; # 1桁目X位置 $POSTNUMF1POSY = 26; # 1-3桁目Y位置 $POSTNUMF1WIDTH = 4; # 1-3桁目送り幅 $POSTNUMF2POSX = 23; # 4桁目X位置 $POSTNUMF2POSY = 26; # 4-7桁目Y位置 $POSTNUMF2WIDTH = 4; # 4-7桁目送り幅 # 差出人 $FROMADR = '横浜市港北区綱島一--二--三'; # 住所 $FROMPCD = '1234567'; # 郵便番号 $FROMLN1 = '田 中'; # 姓 $FROMFN1 = '達夫・律子'; # 名 $FROMLN2 = ' '; # 連名・性 $FROMFN2 = '一郎・次子'; # 連名・名 $FROMOTH = '012-345-6789'; # その他(下寄せ)
LaTeX プリアンブル・ファイル
生成されるハガキ宛名印刷 LaTeX コードの先頭に出力されるコードである。もしフォントなどを変更したい場合は,パッケージ,デフォルト・ローマン書体の指定を追加すればよい。Babel パッケージが指定されているが,外国語が不要なら削ってもよい。
% -*- coding: utf-8; mode: latex; -*-
% LaTeX プリアンブル・ファイル(TeX preamble 原稿)
% 2011 (c) isao yasuda.
\documentclass{jsarticle}
\special{papersize=100mm,148mm}%はがき大きさページサイズ
\usepackage[T2A,T1]{fontenc}%
\usepackage[utf8x]{inputenc}%
\usepackage{plext}%pTeX縦組ツール
\usepackage[russian,english,french,german,japanese]{babel}%多国語
\usepackage[deluxe,expert,multi]{otf}%
\setlength{\textwidth}{100mm}%ハガキ幅
\setlength{\textheight}{148mm}%ハガキ高
\setlength{\oddsidemargin}{-25.4mm}%左横マージン0
\setlength{\topmargin}{-25.4mm}%上マージン0
\setlength{\headheight}{0mm}%
\setlength{\headsep}{0mm}%
\setlength{\unitlength}{1mm}%picture環境単位mm
\pagestyle{empty}%ページ番号なし
\newlength{\namelen}%宛名幅用
\parindent=0pt\relax
mkpostaddr はがき印刷用住所差込 Perl コード
Perl プログラム。現在の Perl 処理系ならモジュール追加なしに実行できるはずである。よほど印刷様式が気に入らない限り,修正は不要のはずである。
#!/usr/bin/perl
# -*- coding: utf-8; mode: cperl; -*-
#
# mkpostaddr はがき印刷用住所差込
# 2011 (C) isao yasuda, All Rights Reserved.
#
# SUMMARY
# ------
# アドレスCSVファイルを読込み,はがき宛名印刷用TeXファイルを生成する
#
# DESCRIPTION
# -----------
# 1. preamble ファイルを読込み,出力する
# 2. コンフィグファイルを読込み,TeX 形式で出力する
# 3. 明細フォームファイルを読込み,form 配列に行展開する
# 4. アドレスcsvファイルを一行ずつ読込み,form パターンに差込み,出力する
#
# USAGE
# -----
# 1. address.csv, post.conf, preamble.tex, form.tex は UTF-8 であること
# 2. コマンドラインは以下のとおり
# % mkpostaddr -c post.conf -f form.tex -p preamble.tex \
# < address.csv > hagaki.tex
# % eplatex hagaki.tex
# % dvipdfmx hagaki.dvi
#
use strict;
use utf8;
use Getopt::Std;
use File::Basename;
binmode(STDOUT, ":utf8");
# コマンドライン引数処理
my %opts = (
'c' => 'post.conf', # configuretion
'f' => 'form.tex', # form.tex
'p' => 'preamble.tex' # preamble.tex
);
Getopt::Std::getopts('c:f:p:', \%opts) || usage();
# プリアンブル出力
open(INP, "<:utf8", $opts{'p'}) ||
die $opts{'p'} . " file not found.\n";
print $_ while (<INP>); close(INP);
# コンフィグ初期値 単位 mm
# 宛先郵便番号
my $POSTNUMT1POSX = 48; # 1桁目X位置
my $POSTNUMT1POSY = 132; # 1-3桁目Y位置
my $POSTNUMT1WIDTH = 6; # 1-3桁目送り幅
my $POSTNUMT2POSX = 68; # 4桁目X位置
my $POSTNUMT2POSY = 132; # 4-7桁目Y位置
my $POSTNUMT2WIDTH = 6; # 4-7桁目送り幅
# 差出人郵便番号
my $POSTNUMF1POSX = 10; # 1桁目X位置
my $POSTNUMF1POSY = 16; # 1-3桁目Y位置
my $POSTNUMF1WIDTH = 4; # 1-3桁目送り幅
my $POSTNUMF2POSX = 24; # 4桁目X位置
my $POSTNUMF2POSY = 16; # 4-7桁目Y位置
my $POSTNUMF2WIDTH = 4; # 4-7桁目送り幅
# 差出人
my $FROMADR = ''; # 住所
my $FROMPCD = ''; # 郵便番号
my $FROMLN1 = ''; # 姓
my $FROMFN1 = ''; # 名
my $FROMLN2 = ''; # 連名・性
my $FROMFN2 = ''; # 連名・名
my $FROMOTH = ''; # その他(下寄せ)
# コンフィグ定義読込
open(INC, "<:utf8", $opts{'c'}) ||
die $opts{'c'} . " file not found.\n";
eval($_) while (<INC>); close(INC);
print <<"EOM";
\\newcount\\cntTOX \\cntTOX=$POSTNUMT1POSX
\\newcount\\cntTOY \\cntTOY=$POSTNUMT1POSY
\\newcount\\cntTOW \\cntTOW=$POSTNUMT1WIDTH
\\newcount\\cntTTX \\cntTTX=$POSTNUMT2POSX
\\newcount\\cntTTY \\cntTTY=$POSTNUMT2POSY
\\newcount\\cntTTW \\cntTTW=$POSTNUMT2WIDTH
\\newcount\\cntFOX \\cntFOX=$POSTNUMF1POSX
\\newcount\\cntFOY \\cntFOY=$POSTNUMF1POSY
\\newcount\\cntFOW \\cntFOW=$POSTNUMF1WIDTH
\\newcount\\cntFTX \\cntFTX=$POSTNUMF2POSX
\\newcount\\cntFTY \\cntFTY=$POSTNUMF2POSY
\\newcount\\cntFTW \\cntFTW=$POSTNUMF2WIDTH
\\begin{document}
EOM
my @frompcd = ("", "", "", "", "", "", "");
if ($FROMPCD) {
@frompcd = split(//, $FROMPCD);
}
# フォーム入力/行展開
open(INF, "<:utf8", $opts{'f'}) ||
die $opts{'f'} . " file not found.\n";
my @form = <INF>; close(INF);
# 住所CSVファイルを読み込み,行毎にはがき整形する
while (<STDIN>) {
utf8::decode($_);
# コメント行(\#),空行は読み飛ばす
next if /^#/; next if /^\s*$/; chomp;
my @addr = split(/,/, $_);
next if ($addr[0] eq "");
my @postnum = split(//, $addr[2]);
my @formwk = @form;
foreach my $corln (@formwk) {
# 宛名1姓00
$corln =~ s/:00:/$addr[0]/;
# 宛名1名01
$corln =~ s/:01:/$addr[1]/;
# 郵便番号 1-7
for (my $i = 1; $i <= 7; $i++) {
$corln =~ s/:$i:/$postnum[$i-1]/;
}
# 住所1: 番地まで
$corln =~ s/:8:/$addr[3]/;
# 住所2: ビル・アパート・部屋
$corln =~ s/:9:/$addr[4]/;
# 会社名
$corln =~ s/:10:/$addr[5]/;
# 部署名
$corln =~ s/:11:/$addr[6]/;
# 宛名2連名姓
$corln =~ s/:12:/$addr[7]/;
# 宛名2連名名
my $ren = $addr[8];
$ren .= "~様" if ($ren);
$corln =~ s/:13:/$ren/;
# 差出人
$corln =~ s/:20:/$FROMADR/;
$corln =~ s/:21:/$FROMLN1/;
$corln =~ s/:22:/$FROMFN1/;
$corln =~ s/:23:/$FROMLN2/;
$corln =~ s/:24:/$FROMFN2/;
for (my $i = 30; $i <= 36; $i++) {
$corln =~ s/:$i:/$frompcd[$i-30]/;
}
$corln =~ s/:25:/$FROMOTH/;
print $corln;
}
print "\\newpage\n";
}
print "\\end{document}\n";
sub usage {
my $prog = basename($0);
die <<"EOM";
Usage: $prog -c config-file -f form-file -p preamble-file
\< address-csv-file \> postcard.tex
-c configuration file (default: post.conf)
-f form TeX file with variables (default: form.tex)
-p preamble definition file (default: preamble.tex)
EOM
}
掲載したアーカイブには Makefile を添付しており,UNIX 系ユーザなら make とすればサンプル PDF が生成される。dvipdfmx OTF パッケージ用マップファイル otf-
% ./mkpostaddr -c post.conf -f form.tex -p preamble.tex \ < address.csv > hagaki.tex % eplatex hagaki.tex % dvipdfmx -f otf-ptex-noembed.map hagaki.dvi
宛名情報の出力様式(フォント,空き,出力位置)などをカスタマイズしたい場合は,form.