Network Users' Group ``wheel'' / Dai ISHIJIMA's Page /
FreeBSDでESC/Pプリンタを使おう

最終更新日: 2002/03/02


FreeBSDでESC/Pプリンタを使おう

(1996年ごろの話題)


★2002年の余談

以下の話は、1996年ごろの話です。 最近のプリンタ、特にカラーインクジェットプリンタ(ESCラスターとか)は 日本語フォントを持っていないものがありますから、 ここでの話は通用しません。


★余談

ここの話は,FreeBSDを前提にしていますが, 他のBSD UNIXでも通用する部分がもちろんたくさんあります。

★準備

まだ書いてません (^^;)

★シンプルな設定

lprコマンドを使って,単純にプリンタにデータを送るだけなら, /etc/printcapに
	lp|local line printer:\
		:lp=/dev/lpt0:sd=/var/spool/output/lpd:lf=/var/log/lpd-errs:
と書けばおっけーです。

ここで,``lp='' はプリンタのデバイスファイルの指定 (通常は/dev/lpt0につなぐと思うのでここままでいいでしょう), ``sd='' はスプールディレクトリの指定です。 スプールディレクトリは,プリンタに送るデータを貯めておく場所です。 ここで指定したディレクトリが存在するかどうかを確認しておきましょう。

★フィルタを使って便利に

先の設定では,単にプリンタにデータを送るだけなので, TeXのdviファイルを印刷したいと思ったら, いちいち
	% jdvi2kps foo.dvi | gs -sDEVICE=epson -r180x180 -q -sOutputFile=- - | lpr
のように長ったらしいコマンドを打つ必要があります。 また,プリンタとUNIXとで使われる文字コードが違うため, 日本語を含むテキストファイルの印字もできません。 そこで, …という設定を説明します。

/etc/printcapには,プリンタに送るデータをフィルタに通して加工する という機能があります。 そのフィルタはprintcapに複数登録でき, 印刷時にどのフィルタを使うかは,lprのオプションで指定します。

printcapへのフィルタの登録は,

	:if=/usr/local/libexec/lpf-escp.text:\
	:vf=/usr/local/libexec/lpf-escp.bin:\
	:df=/usr/local/libexec/lpf-escp.dvi:\
	:cf=/usr/local/libexec/lpf-escp.ps:\
のような書式で行います。ここで,``='' の右辺がフィルタの名称で, 左辺の ``?f'' の ``?'' が lpr のオプションに対応します。 たとえば,
	% lpr -d foo.dvi
のようにlprを実行すると,foo.dvi は ``df='' で指定されている フィルタ (/usr/local/libexec/lpf-escp.dvi) で処理されて, その出力がプリンタに送られます。
	% lpr foo.txt
のようにオプションを指定しなかった場合は,``if='' で指定した フィルタが使われます (逆に,lprには ``-i'' オプションはなかった…はず)。

…というわけで,本セクションの冒頭で想定した printcap

	#	@(#)printcap	0.1 (Dai Ishijima) 2/7/96

	#lp|local line printer:\
	#	:lp=/dev/lpt0:sd=/var/spool/output/lpd:lf=/var/log/lpd-errs:

	#
	#   lpr option  this setting	in lpr(1)
	#   -----------+---------------+------------
	#	none	regular text	regular text
	#	-c	PostScript	cifplot
	#	-d	DVI		DVI
	#	-v	raw data	raster image
	#	-t	half size	troff
	#
	lp|escp|local printer|EPSON ESC/P-24 or compatible:\
		:lp=/dev/lpt0:sd=/var/spool/output/lpd:lf=/var/log/lpd-errs:\
		:if=/usr/local/libexec/lpf-escp.text:\
		:vf=/usr/local/libexec/lpf-escp.bin:\
		:df=/usr/local/libexec/lpf-escp.dvi:\
		:cf=/usr/local/libexec/lpf-escp.ps:\
		:tf=/usr/local/libexec/lpf-escp.small:\
		:mx#0:sh:
こんな感じになります。

ちなみに,``#'' から行末まではコメントです。 これは他のUNIXの設定ファイルと同じですね。 それと,最後の行の ``mx#0'' は,印刷するファイルの大きさに 制限を加えないこと, ``sh'' はバナーページ (だれが印刷したものかを書いた,表紙みたいなページ) を印刷しないことを指示するためのものです。

この設定では,日本語を含む (もちろん含まないのでもかまわないです) テキストファイルはオプションなしで, dviファイルは ``-d'' オプションをつけて, PostScriptファイルは ``-c'' オプションをつけて, バイナリデータ (ESC/P形式データ) は ``-v'' オプションを つけて印刷します。

さて,では次にprintcapで指定した フィルタをつくることにしましょう。

まず,テキストファイルを考えてみます。 ESC/Pプリンタで,日本語混じりのテキストを印刷するためには, 文字の種類が切り替わるときに ``ここからは2バイト文字'' とか ``ここからは1バイト文字'' というエスケープシーケンスを送ってやる必要があります。 ESC/Pプリンタの場合,これらはそれぞれ ``FS &'' と ``FS .'' です。

また,UNIXで使われているJISコードでは,これらのエスケープシーケンスは それぞれ, ``ESC $ B'' と ``ESC ( B'' です。 そこで,これらのエスケープシーケンスをプリンタに合うように 書き換えてやればうまくいきます。 また,JISコード以外のEUCやSJISテキストを印刷したいときは, いったん,JISコードに変換してから処理すればいいでしょう。

以上の処理をまとめると,

  1. nkfで文字コードをJISに変換して
  2. sedでエスケープシーケンスを書き換える
ということになります。 つまり,
	nkf -j | sed -e 's/'"$kin"'/'"$escp_kin"'/g' -e 's/'"$kout"'/'"$escp_kout"'/g'
という処理にかければいいわけです。 ただし,ここで,$kin, $escp_kin, $kout, $escp_kout には, それぞれJIS, ESC/Pのエスケープシーケンスが設定されています。 これを設定するには,(cshスクリプトだと)
	set  kin=`printf '\033$B'`
	set kout=`printf '\033(B'`
	set  escp_kin=`printf '\034\\&'`
	set escp_kout=`printf '\034\\.'`
とすればいいでしょう。 (FreeBSD以外だと,printf(1)コマンドがないかもしれません。 そのときはてきとーに工夫してみてください)

次にPostScriptファイルの場合を考えてみましょう。 これは,gs(1)にかけて,

	gs -sDEVICE=epson -r180x180 -sPAPERSIZE=a4 -q -sOutputFile=- -
というコマンドで処理すればいいです。

dviファイルの場合は,dvi→PostScript変換フィルタをつけて,

	jdvi2kps | gs -sDEVICE=epson -r180x180 -sPAPERSIZE=a4 -q -sOutputFile=- -
とします。

さて,これでメイン部分はできました。 つぎに,用紙とのかねあいを考えてみましょう。 A4サイズの用紙は,横210mmです。 A4用紙を使ったときの印字可能領域は, プリンタにもよりますが,だいたい8インチくらいです。 通常のプリンタの初期設定では文字の間隔が1/10インチなので, この場合,横80桁印刷できることになります。 しかし, このままでは余白が狭すぎてとじしろがとれないので, 文字間隔を1/12インチ (エリートサイズ) にしましょう。 エリートサイズにするには,``ESC M'' というエスケープシーケンスを 送ります。 また左側の余白を設定するには,``ESC l'' というエスケープシーケンスを 送ります。

説明の順序が逆ですが, これらのモロモロの処理をまず行って,先に説明したファイル処理を おこなったのが, これ

	#! /bin/csh -f
	#
	#   lpf-escp -- ESC/Pプリンタ用のフィルタ
	#
	#   lpf-escp.text: テキストファイル出力用 (日本語コードの変換などを行う)
	#   lpf-escp.bin: 入力をそのままプリンタに送る時に使う
	#   lpf-escp.ps, lpf-escp.dvi: それぞれ ps, dviファイル用
	#   lpf-escp.small: 縮小印刷用
	#
	#   revision history:
	#	0.0: Jan. 5, 94 by Dai Ishijima
	#	1.0: Feb. 6, 96
	#
	
	set path=(/usr/bin /bin /usr/local/bin)
	
	set prog=$0
	set type=$prog:e
	set basename=$prog:r
	
	if (x$type == x) then
		foreach t (text bin ps dvi small)
			rm -f $basename.$t
			ln -s $prog $basename.$t
		end
		exit 0
	endif
	
	# プリンタ初期化
	#	ESC @		リセット
	#	ESC P ESC Q 80	用紙サイズを8インチに設定
	#		ESC P     10文字/インチ
	#		ESC Q 80  用紙幅を80文字に
	#	ESC l 5		左マージンを1/2インチ (5文字分) に設定
	set init='\033@\033P\033Q\120\033l\005'
	
	#	ESC x 0		高速 (ドラフト) 印字指定
	#	FS x 1		漢字高速印字指定
	#	ESC M		エリートサイズ (12文字/インチ) 指定
	#	FS S 3 3	漢字の左右余白設定
	set init="$init"'\033x0\034x1\033M\034S\003\003'
	
	# タブストップの設定 (ESC D): 8文字ごと
	set init="$init"'\033D\010\020\030\040\050\060\070\100\110\120\010'
	
	# 印刷後、改ページ (^L) してリセット (ESC @)
	set fin="\014\033@"
	
	set  kin=`printf '\033$B'`
	set kout=`printf '\033(B'`
	set  escp_kin=`printf '\034\\&'`
	set escp_kout=`printf '\034\\.'`
	
	printf "$init"
	if ($type == text) then
		nkf -j |\
		sed -e 's/'"$kin"'/'"$escp_kin"'/g' -e 's/'"$kout"'/'"$escp_kout"'/g'
	else if ($type == ps) then
		gs -sDEVICE=epson -r180x180 -q -sOutputFile=- -
	else if ($type == dvi) then
		jdvi2kps | gs -sDEVICE=epson -r180x180 -q -sOutputFile=- -
	else if ($type == small) then
		nkf -s | slpr
	else if ($type == bin) then
		cat
	else
		cat
	endif
	printf "$fin"
です。