スキップしてメイン コンテンツに移動

LaTeXで宛名ラベルシールの差し込み印刷をする

この記事は TeX & LaTeX Advent Calendar 2021 の20日目の記事です。

19日目は hid_alma1026 さん、21日目は 7danmoroboshi さんです。

 

はじめに

業務でラベルシール用宛名ラベルの作成にラベル屋さんというソフトを利用しています。しかし公式サイトの使い方を見る限り、連名の有り無しなどの条件分岐に対応したラベル作りに対応できなさそうです。そこでLaTeXのtikzとtcolorbox, datatool, intcalcパッケージなどを利用して宛名ラベルの差し込み印刷に挑戦してみました。

TeXエンジンは、フォントの変更がしやすいという噂のLuaTeX-jaを利用することにしました。

datatoolはデータセットからdata plotや表作成などが行えるLaTeXパッケージです。日本語では

で使い方を見ることができます。csvなどの外部データを利用することもできて、今回は作成したcsvファイルを読み込み、定型フォーマットに文字列を流し込むのに利用しました。


準備

まずは宛名ラベルの差し込み印刷に利用するcsvファイルを用意します。今回は

を利用して、次の画像ようなcsvファイル(personal_information.csv)を作成しました。


csvファイルのヘッダ部分は取り除いています。ヘッダ部分がある場合もdatatoolの記述を変えれば利用できるようです。各列の意味は次の通りです。括弧内はdatatoolで扱う際のkeyを表しています。
  1. 名前(Name)
  2. 郵便番号(PostalCode)
  3. 住所1(Address)
  4. 住所2(address)
  5. ご家族様表記の有無(ToFamily)
  6. 連名1(Family)
  7. 連名2(family)

出力結果

上のcsvファイルを元に作成した宛名ラベルのpdfファイルの画像を載せておきます。あくまでも画像の住所・氏名はダミーで実在しません。


1枚目の画像は印刷後に余ったラベルシールの再利用を想定して、ラベル開始位置を指定できるようにし、開始位置をずらしたものです。画像では4番目のラベル位置から宛名を配置しています。その他に連名を入れたいもの、ご家族様表記を入れたいものなどを判別してラベルが作成されるようにしています。画像では枠があるように見えますが、印刷には出てきません。

コードの紹介

上記画像の宛名ラベルを作成するためのLaTeXファイルの内容を紹介します。
ここではラベルを印刷するシールはA-Oneの75312番を想定しています。シート1枚に対して12面のラベルがあり、その寸法に合わせてnewlengthを定義しています。タイプセットは2回必要です。
\documentclass[lualatex,a4paper,ja=standard]{bxjsbook}

\usepackage[haranoaji]{luatexja-preset}
\usepackage[T1]{fontenc} %入力ファイル中でアクセント記号付きの欧文を扱う
\usepackage{lmodern}% Latin Modern フォントを使う

\usepackage{etoolbox}

\usepackage[math=pgfmath,utf8=true]{datatool}
\usepackage[utf8]{inputenc}
\usepackage{intcalc} %modの計算に使用

\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{calc,math}
\usepackage{tcolorbox}


%新しい長さのコマンドを設定
\newlength{\myleftmargin}
\newlength{\myrightmargin}
\newlength{\mytopmargin}
\newlength{\mylabelwidth}
\newlength{\mylabelheight}
\newlength{\mymidspace}

\setlength{\myleftmargin}{19.3mm}
\setlength{\myrightmargin}{19.3mm}
\setlength{\mytopmargin}{21.5mm}
\setlength{\mylabelwidth}{83.8mm}
\setlength{\mylabelheight}{42.3mm}
\setlength{\mymidspace}{3.8mm}

%ページ番号を表示させない
\pagestyle{empty}

%yatex用の記述
%#! lualatex label.tex


%tikzpicture環境の定義
\tikzset{every picture/.style={%
remember picture, overlay,
execute at begin picture=%picture環境の最初に行う処理
{%tikzのmath libraryを使って,各labelの左上の端点位置を計算しておく.
\coordinate (P) at (current page.north west); %紙面左上の端点の座標
\tikzmath{%各ページにlabelが12枚なので12個の点の座標を配列として定義.
int \i,\j;
coordinate \p;
\p0 = (P)+(\myleftmargin, -\mytopmargin);%配列の番号は0から11まで.
\p1 = (\p0)+(\mylabelwidth + \mymidspace, 0);
 for \i in {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}{
 \j =\i+2;
 \p\j = (\p\i) + (0, -\mylabelheight);
 };%tikzmathの終わり
 }}}
}


%新しいtcolorbox環境の定義
\newtcolorbox[blend into=tables]{addresslabel}{%blend into=tablesで,tcolorbox環境内でtabular環境を使えるようにする.
colback=white,%box内の背景色
%colframe=white,%box枠の色
width =\mylabelwidth,%boxの幅
height=\mylabelheight,%boxの高さ
lower separated=false,%upperとlowerの境界線を消す
middle = 0pt,%境界線と文章の距離
space to lower,%box内の高さの空きスペースをすべてlowerに渡す
boxrule=0mm,%枠線の幅
valign lower=center,%lower部分の垂直方向の位置揃え
valign upper=top,%upper部分の垂直方向の位置揃え
halign lower=center,%lower部分の水平方向の位置揃え
halign upper=flush left,%upper部分の水平方向の位置揃え
fontlower=\sffamily\bfseries,%lower部分のフォント変更
}

%xparseを使ったコマンドの定義
\NewDocumentCommand\AddressLabel{m m m m m m o o}{
%#1:ラベル位置, #2:ご家族様表記の有無, #3:氏名, #4:郵便番号, #5:住所1, #6:住所2, #7:連名1, #8:連名2
\begin{tikzpicture}[every picture]
\node[inner sep=0pt,anchor=north west] at (\p{#1}){%ラベルを置く位置(ラベル左上端点の座標)
\begin{addresslabel}
%upperpart
\fontsize{10pt}{12pt}\selectfont%
〒{#4}
\par
\hspace{1\zw}{#5}
\par
\hspace{1\zw}{#6}
\tcblower
%lowerpart
\fontsize{15pt}{1.58\zh}\selectfont%
\begin{tabular}{r}%
{#3}~様
\IfNoValueTF{#7}{}{\\ {#7}~様}
\IfNoValueTF{#8}{}{\\ {#8}~様}
\ifnumequal{#2}{1}{\\ {ご家族}~様}{}
\end{tabular}
\end{addresslabel}
};%nodeの終わり
\end{tikzpicture}
}


\newcounter{posnum}%ラベルの位置を表すカウンターの定義
\newcounter{initposnum}%最初のラベル位置を表すカウンター
\newcounter{linenum}%アドレスデータの行番号
\setcounter{initposnum}{3}%最初のラベル位置(0,1,...,11で指定)
\begin{document}

%datatoolパッケージでcsvファイルを読み込む
%personal_information.csvはヘッダー無しで,第1列から順にName, PostalCode, etc.を表す.dataという名前にする.
%Name=代表者名, PostalCode=郵便番号, Address=住所1, address=住所2, ToFamily=ご家族様表記の有無, Family=連名1, family=連名2
\DTLloaddb[noheader,keys={Name,PostalCode,Address,address,ToFamily,Family,family}]{data}{personal_information.csv}

%上で読み込んだdataの各行に対して処理を行う.
\begin{DTLenvforeach}{data}{\Name=Name, \PostalCode=PostalCode, \Address=Address, \address=address, \ToFamily=ToFamily, \Family=Family, \family=family}
%\DTLcurrentindexがデータ行番号を表す.1ページあたりのラベル数が12なので,ラベル位置はこれを12で割った余りとして計算.
\setcounter{linenum}{\intcalcAdd{\DTLcurrentindex}{\theinitposnum -1}}
\setcounter{posnum}{\intcalcMod{\thelinenum}{12}}
%データ行番号が12を超えていたら,12の倍数ごとに改ページをする.
\ifnum\thelinenum>11\ifnum\theposnum = 0 \newpage\fi\fi 
\DTLifstringeq{\Family}{}{%連名の有無で条件分岐
 \AddressLabel{\theposnum}{\ToFamily}{\Name}{\PostalCode}{\Address}{\address}%
 }{%
 \DTLifstringeq{\family}{}{%
 \AddressLabel{\theposnum}{\ToFamily}{\Name}{\PostalCode}{\Address}{\address}[\Family]%
 }{%
 \AddressLabel{\theposnum}{\ToFamily}{\Name}{\PostalCode}{\Address}{\address}[\Family][\family]%
 }}
\end{DTLenvforeach}
\end{document}
ループ処理があるため実行速度は遅めです。tcolorboxの設定でcolframe=whiteとすれば、上の画像にあったboxの枠も消えます。

intcalcパッケージは、剰余計算で利用しています.\intcalcAdd, \intcalcModはこのパッケージで定義されています。

xparseパッケージとtcolorboxパッケージを利用してAddressLabelというコマンドを作りそれをdatatoolパッケージで定義されるDTLenvforeach環境内でループ処理させています。最初は、AddressLabelコマンドのオプションの引数のところを必須引数にして、引数が空文字であれば空文字を入れるようにetoolboxのifstremptyコマンドで記述しようとしたのですが、Familyやfamilyキーが空文字でもDTLenvforeach環境内での\Familyなどのコマンドは空文字と判断されなかったため、これらをオプション引数にして条件分岐で対応しました。トークンの展開順序などが関係しているのでしょうか。

最後に

今回作成したラベルはシンプルなものですが、tikzを使って色々装飾できそうです。
しかし作ってはみたものの、事務の方にLaTeXを使わせるわけにもいかないので実際には使わないかな。

このブログの人気の投稿

OpenCv-PythonとpdfLaTeXで自炊pdfファイルの位置調整

この記事は TeX & LaTeX Advent Calendar 2021 の11日目の記事です. 10日目は t_kemmochi さん,12日目は yukishita さんです.   動機  書籍の自炊にブックエッジスキャナーの AvisionのFB2280E を利用しています。書籍を裁断せずに1ページずつスキャンを行うため、本の開き具合などの要因で本の序盤、中盤、終盤で得られるスキャン画像の位置ずれが大きくなります。以前からpdfLaTeXを利用して位置調整をしていたのですが、OpenCvを利用して自動化できそうだったので試してみました。 やること 本記事では、pdf化した文書画像の版面(文字の印刷された部分の意味で使います)を半自動的に計算してpdfの画像の位置調整をするために、OpenCvとpdfLaTeXを利用する方法を解説します。手順としては Pythonの画像認識用ライブラリであるOpenCvを利用して版面を計算する。 テンプレートエンジンライブラリのJinja2を使って画像のバウンディングボックスなどを記述したLaTeXファイルを作成する。 pdfLaTeXでpdfを読み込み、位置の調整されたpdfを作成する。 という流れになっています。作業環境としては、 Visual Studio CodeをRemove - WSL拡張機能と併用 しています。PythonやそのライブラリはWSL上のUbuntuにインストールし、他にもpdfファイルを他のファイル形式にするためにpoppler-utilsなんかもインストールしました。 参考記事 OpenCvを利用した文書画像のレイアウト解析については ブログSomething Like Programming内の記事 Document Layout Analysis githubリポジトリ rbaguila/document-layout-analysis OpenCv-Pythonチュートリアル を参考にしました。 pdfLaTeXがpdf加工に使えるという話と、pdfpagesパッケージの存在は doraTeXさんのブログTeX Alchemist Onlineの記事 pdfTeX による見開きPDFの結合・分割 で知ったように思います。 画像pdfをpdfpagesで取り込む ま...

定理環境をmdframedからtcolorboxへ乗り換え

追記:2016/05/02 以前に掲載していた定理環境のマクロでは、カウンターが変化しないような記述をしてしまっていたので、全面的に書き換えました。 追記:2016/06/06 tcolorboxのオプションを追加できるように書き直しをしました( tcolorboxを使った定理環境 )。 LaTeXの話です。 これまで定理環境の修飾にmdframed.styを利用してきました。 mdframedを用いた定理環境の修飾(platex+dvipdfmx, tikz) しかし上の投稿で用いた記述をしていると、定理環境がページの下部にきたとき、まれに以下のように環境が新しいページに送られてしまい変なところで改ページが起こります。 TeX-LaTeX Stack Exchangeでも同様の不具合が報告されていて、mdframed.styの作者が回答して解決しているようなのですが、私の場合は上手く行きませんでした。タイトル部分の位置の計算に問題があるようです。 そういう訳で、mdframed.styよりも高い表現力を持つtcolorbox.styには興味を持っていました。今回は、mdframed.styで記述していた部分を、ソースの変更無しにtcolorboxで置き換えてみたので、その紹介をします。 tcolorbox.styで置き換えた結果は次のようになりました。 見た目はほとんど変わっていません。中のboxは別のtcolorbox環境です。 この定理環境のソースコードは次のようになります。 \usepackage{tcolorbox} \usepackage{varwidth} \tcbuselibrary{breakable} \tcbuselibrary{skins} \definecolor{frameinnercolor}{RGB}{49,44,44} \newcounter{theorem} \numberwithin{theorem}{section}% numberwithinはamsmath.styで定義されている \newenvironment{theorem}[2][]{% %#1 = タイトル, #2 = 定理環境名 \refstepcounter{theorem}% \newtcolorbox{...

定理を再掲したときに定理番号も揃える(amsmathのtagと似た挙動の定理環境を作る).

LaTeXの話題です.amsmath.styで定義されているtagコマンドは,数式環境の式番号部分を自由な文字列で置き換えることができるようになっています.下に例を挙げます. この画像を生成するLaTeXのコードは次のようになります. \documentclass[a4paper,dvipdfmx,uplatex]{jsarticle} \usepackage[dvipdfmx,bookmarks=true,bookmarksnumbered=true,% ,colorlinks=true,linkcolor=blue]{hyperref}% \usepackage{showkeys} \usepackage{amsmath} \numberwithin{equation}{section} Unknown environment 'document' 最初のequation環境にeq:eulerというlabelをつけ,第2のequation環境ではtagコマンドを使って数式番号部分に¥ref{eq:euler}と書くことで,実際に表示される式番号が第1のequation環境のものと同じになっています.この第2のequation環境にはeq:euler2というlabelを付けており,これを¥eqref{eq:euler2}と参照すると表示される番号は第1のequation環境のものであるにも関わらず,リンクをクリックすると第2のequation環境にジャンプします. このような現象が起こるのは,上記のファイルをタイプセット...