gnuplotでハガキの宛名作成

gnuplotの「データから画像を作成する」という特性を考えると、これは住所録(=データ)からハガキの宛名(画像)を作るのに使えるのではないかと思い立ちました。実際、gnuplot4.2以降ではデータファイル中の文字列を読み取るstringcolumn()関数やデータファイル中の文字列をグラフに表示するplot ** with labelsが使えるので、これらの機能を用いてはがきの宛名を作成することができます。

スクリプト例

以下の例は、タブ切りの住所録ファイルから宛名のPostScriptファイルを生成するスクリプトです。住所録ファイルaddress.txtは、こちらのようなタブ切りのテキストファイルです。差出人の情報ファイルmy_address.txtも同じ形式のテキストファイルです。以下のスクリプトはこれらのファイルから読み取った情報から画像ファイルを生成します。

#文字列関数の定義
# strの中でtargetよりも前の部分文字列を返す
substr_str_before(str,target)=substr(str, 1, strstrt(str,target)-1)
# strの中でtargetよりも後の部分文字列を返す
substr_str_after(str,target)=substr(str,strstrt(str,target)+strlen(target),strlen(str))
# 再帰表現を利用して、strのindexより後の文字列のtargetをsubstに全て置換する
strsubst_sub(str,index,target,subst)=strstrt(str[index:],target)==0 ? str :\
     strsubst_sub( str[:index-1] . substr_str_before(str[index:],target) . \
     subst . substr_str_after(str[index:],target),\
     index+strstrt(str[index:],target)+strlen(subst)-strlen(target),target, subst)
# strの中のtargetをsubstに置換する
strsubst(str,target,subst)=strsubst_sub(str,1,target, subst)


# 半角数字を全角に、-(ハイフン)を|(縦棒)にそれぞれ変換する関数
strform(str)=strsubst(strsubst(strsubst(strsubst(strsubst(strsubst\
     (strsubst(strsubst(strsubst(strsubst(strsubst(\
     str, "-", "|"), "0", "0"), "1", "1"), "2", "2"),\
     "3", "3"), "4", "4"), "5", "5"), "6", "6"),\
     "7", "7"), "8", "8"), "9", "9")


set border 0
unset xtics
unset ytics

set tmargin 0
set rmargin 0
set bmargin 0
set lmargin 0

set xrange [0:100]
set yrange [0:148]


file="address.dat"        # 住所録ファイル (タブ切り)
myfile="my_address.dat"   # 差出人の住所ファイル(タブ切り)

set datafile separator "\t"


name=6  # 名前のあるColumn
add1=3  # 住所1のあるColumn
add2=4  # 住所2のあるColumn
add3=5  # 住所3のあるColumn
num1=1  # 郵便番号前半のあるColumn
num2=2  # 郵便番号後半のあるColumn

INI=0  # 住所録の何人目から作成をスタートするか? (1人目 = 0)
FIN=1  # 住所録の何人目まで宛名を作成するか?

if (exist("TERM")==0 || TERM eq "WIN") n=INI



font_address       = "Ryumin-Medium-EUC-V,17.5"  # 受取人住所用のフォント
font_name          = "Ryumin-Medium-EUC-V,30"    # 受取人名前用のフォント
font_postnumber    = "Arial,15"                  # 受取人郵便番号用のフォント
font_my_address    = "Ryumin-Medium-EUC-V,8.5"   # 差出人住所用のフォント
font_my_name       = "Ryumin-Medium-EUC-V,12.5"  # 差出人名前用のフォント
font_my_postnumber = "Arial,7.5"                 # 差出人郵便番号用のフォント


set multiplot

# 受取人の住所の表示
plot file u (90):(120):(strform(stringcolumn(add1))) every ::n::n \
     with labels font font_address notitle,\
     file u (80):(115):(strform(stringcolumn(add2))) every ::n::n \
     with labels font font_address notitle,\
     file u (70):(110):(strform(stringcolumn(add3))) every ::n::n \
     with labels font font_address notitle

# 受取人の名前の表示
plot file u (50):(125):(stringcolumn(name)." 様")  every ::n::n \
     with labels font font_name notitle

# 受取人の電話番号の表示
plot file u (47.5):(133):(substr(stringcolumn(num1),1,1)) every ::n::n with labels font font_postnumber notitle,\
     file u (54.6):(133):(substr(stringcolumn(num1),2,2)) every ::n::n with labels font font_postnumber notitle,\
     file u (61.7):(133):(substr(stringcolumn(num1),3,3)) every ::n::n with labels font font_postnumber notitle,\
     file u (69.3):(133):(substr(stringcolumn(num2),1,1)) every ::n::n with labels font font_postnumber notitle,\
     file u (76.1):(133):(substr(stringcolumn(num2),2,2)) every ::n::n with labels font font_postnumber notitle,\
     file u (82.9):(133):(substr(stringcolumn(num2),3,3)) every ::n::n with labels font font_postnumber notitle,\
     file u (89.7):(133):(substr(stringcolumn(num2),4,4)) every ::n::n with labels font font_postnumber notitle

# 差出人の住所の表示
plot myfile u (25):(85):(strform(stringcolumn(3).stringcolumn(4))) \
     with labels font font_my_address notitle,\
     myfile u (19):(80):(strform(stringcolumn(5)))   with labels font font_my_address notitle

# 差出人の名前の表示
plot myfile u (10):(78):(strform(stringcolumn(6))) with labels font font_my_name notitle

# 差出人の郵便番号の表示
plot myfile u ( 7.5):(22):(substr(stringcolumn(num1),1,1)) with labels font font_my_postnumber notitle,\
     myfile u (11.5):(22):(substr(stringcolumn(num1),2,2)) with labels font font_my_postnumber notitle,\
     myfile u (15.5):(22):(substr(stringcolumn(num1),3,3)) with labels font font_my_postnumber notitle,\
     myfile u (21.5):(22):(substr(stringcolumn(num2),1,1)) with labels font font_my_postnumber notitle,\
     myfile u (25.5):(22):(substr(stringcolumn(num2),2,2)) with labels font font_my_postnumber notitle,\
     myfile u (29.5):(22):(substr(stringcolumn(num2),3,3)) with labels font font_my_postnumber notitle,\
     myfile u (33.5):(22):(substr(stringcolumn(num2),4,4)) with labels font font_my_postnumber notitle
     
unset multiplot


# デフォルトで入る左下の50pt,50ptのマージンを消す (1pt = 1/72inch = 2.54/72 cm)
if (exist("TERM")==0 || TERM eq "WIN")  \
     set origin -2.54/72.0*50/10.0,-2.54/72.0*50/14.8

n=n+1

if (exist("TERM")==0 || TERM eq "WIN") \
     n=INI; set out "postcard.ps"; \
     TERM="PS";\
     set term post portrait enhanced size 10cm,14.8cm


if (n <= FIN) reread


TERM="WIN"
set out
set term win
plot "+" using (50):(50):("Finished") with labels font "Arial,50" notitle

このスクリプトを実行すると、以下のようなファイルができます。

生成したファイルの1ページ目
生成したファイルの2ページ目

実行結果:postcard.ps

このようにgnuplotで宛名の画像ファイルを作成することができました。これからの年賀状シーズンに、ぜひご利用下さい。

スクリプト例の説明

#文字列関数の定義
# strの中でtargetよりも前の部分文字列を返す
substr_str_before(str,target)=substr(str, 1, strstrt(str,target)-1)
# strの中でtargetよりも後の部分文字列を返す
substr_str_after(str,target)=substr(str,strstrt(str,target)+strlen(target),strlen(str))
# 再帰表現を利用して、strのindexより後の文字列のtargetをsubstに全て置換する
strsubst_sub(str,index,target,subst)=strstrt(str[index:],target)==0 ? str :\
     strsubst_sub( str[:index-1] . substr_str_before(str[index:],target) . \
     subst . substr_str_after(str[index:],target),\
     index+strstrt(str[index:],target)+strlen(subst)-strlen(target),target, subst)
# strの中のtargetをsubstに置換する
strsubst(str,target,subst)=strsubst_sub(str,1,target, subst)

# 半角数字を全角に、-(ハイフン)を|(縦棒)にそれぞれ変換する関数
strform(str)=strsubst(strsubst(strsubst(strsubst(strsubst(strsubst\
     (strsubst(strsubst(strsubst(strsubst(strsubst(\
     str, "-", "|"), "0", "0"), "1", "1"), "2", "2"),\
     "3", "3"), "4", "4"), "5", "5"), "6", "6"),\
     "7", "7"), "8", "8"), "9", "9")

この部分は「便利な文字列関数」で紹介している、strsubst()関数を定義しています。また、この関数を使って、半角数字を全角に、-(ハイフン)を|(縦棒)にそれぞれ変換する関数strform()関数を定義しています。これは、数字を縦書きにするときに半角文字だとずれて見えてしまうためです。

set border 0
unset xtics
unset ytics

set tmargin 0
set rmargin 0
set bmargin 0
set lmargin 0

# ハガキの大きさ = 100mmx148mm なので、1座標=1mmに対応させる。
set xrange [0:100]
set yrange [0:148]

この部分では、borderticsを非表示にし、マージンを全てゼロにします。また、x座標とy座標の1をどちらも1mmに対応させるため、xrangeyrangeをそれぞれ[0:100][0:148]に指定しています。なお、ここで想定している官製はがきの大きさは、100mm×148mmです。

file="address.dat"        # 住所録ファイル (タブ切り)
myfile="my_address.dat"   # 差出人の住所ファイル(タブ切り)

set datafile separator "\t"

name=6  # 名前のあるColumn
add1=3  # 住所1のあるColumn
add2=4  # 住所2のあるColumn
add3=5  # 住所3のあるColumn
num1=1  # 郵便番号前半のあるColumn
num2=2  # 郵便番号後半のあるColumn

INI=0  # 住所録の何人目から作成をスタートするか? (1人目 = 0)
FIN=1  # 住所録の何人目まで宛名を作成するか?

この部分では、住所録と差出人の住所ファイルの名前をそれぞれ指定しています。また、ファイルの区切りをタブにします。次に、これらのファイルの中身を指定します。ファイルの何列目に郵便番号が入っているか、などを指定することができます。この部分は自分の住所録ファイルに合わせて変更してください。最後のINI=0FIN=1の部分では住所録の何人目から何人目までの宛名を作成するかを指定できます。

if (exist("TERM")==0 || TERM eq "WIN") n=INI

ループの最初に変数nを初期化しています。

font_address       = "Ryumin-Medium-EUC-V,17.5"  # 受取人住所用のフォント
font_name          = "Ryumin-Medium-EUC-V,30"    # 受取人名前用のフォント
font_postnumber    = "Arial,15"                  # 受取人郵便番号用のフォント
font_my_address    = "Ryumin-Medium-EUC-V,8.5"   # 差出人住所用のフォント
font_my_name       = "Ryumin-Medium-EUC-V,12.5"  # 差出人名前用のフォント
font_my_postnumber = "Arial,7.5"                 # 差出人郵便番号用のフォント

フォントを指定します。自分の好きなフォントを使って構わないのですが、その場合若干微調整が必要になるかもしれません。

set multiplot

plot file u (90):(120):(strform(stringcolumn(add1))) every ::n::n \
     with labels font font_address notitle,\
     file u (80):(115):(strform(stringcolumn(add2))) every ::n::n \
     with labels font font_address notitle,\
     file u (70):(110):(strform(stringcolumn(add3))) every ::n::n \
     with labels font font_address notitle

....

unset multiplot

plot *** with labels機能を用いて、文字列を出力していきます。なお、stringcolumn(col)は今読んでいるデータファールのcol列のデータを文字列として取得する関数です。これで取得した文字列を、さらにstrform(str)関数で整形(半角→全角の変換など)をしてから表示します。

# デフォルトで入る左下の50pt,50ptのマージンを消す (1pt = 1/72inch = 2.54/72 cm)
if (exist("TERM")==0 || TERM eq "WIN")  \
     set origin -2.54/72.0*50/10.0,-2.54/72.0*50/14.8

PostScriptファイルにはデフォルトではファイルの左下に50pt×50ptのマージンが入ってしまうようです。これを消すために、set originで原点を左下にずらします。

n=n+1

if (exist("TERM")==0 || TERM eq "WIN") \
     n=INI; set out "postcard.ps"; \
     TERM="PS";\
     set term post portrait enhanced size 10cm,14.8cm


if (n <= FIN) reread

変数nをインクリメントし、ループの一回目の場合のみはターミナルとアウトプットファイルを変更します。nFIN以下の場合はファイルを再度読み込んでループさせます。

TERM="WIN"
set out
set term win
plot "+" using (50):(50):("Finished") with labels font "Arial,50" notitle

最後に、ループが終わったらターミナルとアウトプットを戻して最後にFinishedという文字列を表示させます。