9.4. プリンタ設定上級編

この節では、特殊な形式のファイルを印字するためのフィルタ、 ヘッダページ、ネットワーク越しのプリンタへの印字、そして、 プリンタ使用の制限や課金について説明しています。

9.4.1. フィルタ

LPD は、ネットワークプロトコル、キュー、アクセス制御などの 印刷にかかわるさまざまな点を扱いますが、 実際の作業のほとんどは フィルタによっておこなわれています。 フィルタは、プリンタと通信し、 プリンタのデバイス依存性や特殊な要求を扱うプログラムです。 簡単なプリンタ設定では、 プレインテキストのためのフィルタをインストールしました。 このプレインテキストフィルタは、 ほとんどのプリンタで機能する極めて単純なものでした (「 テキストフィルタのインストール」を参照)。

しかしながら、形式変換やプリンタ課金、特定のプリンタの癖、 など をうまく利用するためには、 フィルタがどのように機能するかという ことを理解しておくべきです。これらの側面を扱うことは、 最終的には、フィルタの責任であるからです。 そして、これは悪い情報ですが、ほとんどの場合において、 あなた自身が フィルタを供給する必要があるということです。また都合のよいことには、 たくさんのフィルタが一般的に利用できるということです。 もしフィルタがなかったとしても、 普通はフィルタを作るのは簡単です。

FreeBSD にも、プレインテキストを印字させることができる /usr/libexec/lpr/lpf というフィルタが 1 つ付いています (このフィルタはファイルに含まれるバックスペースやタブを扱います。 また、課金をすることもできますが、 できることはこれだけしかありません)。 いくつかのフィルタとフィルタの構成要素は FreeBSD Ports Collection にもあります。

この節で述べることは次の通りです。

9.4.1.1. フィルタはどのように機能しているか

既に言及したように、フィルタとは、プリンタにデータを送る際に、 デバイスに依存した部分を取り扱うために LPD によって起動される実行プログラムです。

LPD がジョブ中のファイルを印字しようとするとき、 LPD はフィルタプログラムを起動します。このとき、 フィルタの標準入力を印字するファイルに、 標準出力をプリンタに、そして、標準エラー出力を エラーログファイル (/etc/printcap 内の lf 項目で指定されたファイル、または、 指定されていない場合は、デフォルトとして /dev/console) にセットします。

LPD が起動するフィルタと、その引数が何であるかは、 /etc/printcap ファイルの内容と、ジョブの起動時にユーザが指定した lpr(1) コマンドの引数に依存しています。 たとえば、ユーザが lpr -t と入力した場合は、 LPD は出力先のプリンタ用の tf 項目で指定されている troff 用のフィルタを起動させるでしょう。 ユーザがプレインテキストの印字を指示したときは、 if で指定されたフィルタが起動されるでしょう (このことはほとんどの場合にあてはまります。 詳細については、「 出力フィルタ」をご覧ください)。

/etc/printcap で指定可能なフィルタは次の3種類があります。

  • テキストフィルタ (LPD のドキュメントでは紛らわしいことに 入力フィルタと呼んでいますが) は一般のテキストの印字を扱います。これはデフォルトのフィルタと 考えてください。LPD では、すべてのプリンタに対して、 デフォルトでプレインテキストが印字できることを期待しています。 さらに、バックスペースやタブを正しく扱い、また、 他の特殊な文字が入力されてもプリンタに混乱を来さないように するのはテキストフィルタの仕事であると考えています。 プリンタの使用に対して課金をしなくてはならない環境にあ るときは、テキストフィルタが印字したページ数を数える作 業もしなくてはなりません。この作業は、通常、印字した行 数を数え、これをプリンタが 1 ページ当たりに印字できる行 数と比較することでおこなわれます。 テキストフィルタは、次のような引数を付けて起動されます。

    filter-name [-c] -wwidth -llength -iindent -n login -h host acct-file

    ここで、
    -c

    lpr -l によってジョブが入力されたときに与えられます。

    width

    /etc/printcap で指定された pw (page width) 項目の値が与えられます。デフォルトは、 132 です。

    length

    pl (page length) 項目で指定された値が与えられます。 デフォルトは 66 です。

    indent

    lpr -i によって与えられた字下げの量で、 デフォルトは 0 です。

    login

    ファイルを印字したユーザのアカウント名が 与えられます。

    host

    ジョブが入力されたホスト名が 与えられます。

    acct-file

    af 項目で指定されている課金データファイル の名前が与えられます。



  • 変換フィルタは、 特定のファイル形式をプリンタ が紙に印字できるようなものに変換します。たとえば、 プリンタで ditroff 組版データを直接印字することはできません。 しかし、ditroff データをプリンタが消化し、 印字することができる形式へ変換するために、ditroff ファイル用フィルタをインストールすることができます。 「 変換フィルタ」 で、これらに関するすべてについて説明します。 プリンタの課金をする必要がある場合は、 変換フィルタでも印字ページを数える作業が必要となります。 変換フィルタは次の引数をとって起動されます。

    filter-name -xpixel-width -ypixel-height -n login -h host acct-file

    ここで、pixel-width は、 px 項目で指定された値 (デフォルトは 0)、 pixel-height は、 py 項目で指定された値 (デフォルトは 0) です。

  • 出力フィルタは、 テキストフィルタが指定されて おらず、かつ、 ヘッダページの出力が許可されている場合にのみ使われます。 「 出力フィルタ」で、これらのことについて説明します。 出力フィルタに対する引数は次の 2 つだけです。

    filter-name -wwidth -llength

    ここで、-w-l は、 テキストフィルタの場合と同じです。

フィルタは、次に示す終了状態をもってプログラムを exit するべきです。

exit 0

フィルタがファイルを正常に印字した場合。

exit 1

フィルタはファイルの印字に失敗したが、 LPD に再度ファイルの印字を試みて欲しい場合。 この終了状態で終了した場合、LPD はフィルタを再スタートします。

exit 2

フィルタはファイルの印字に失敗し、かつ、LPD に再出力を試みて欲しくない場合。この場合、LPD はそのファイルを放棄します。

FreeBSD に付属するテキストフィルタ /usr/libexec/lpr/lpf は、FORM FEED 文字が送られたときやプリンタ使用に対する課金をどのようにするかを決定するために、 ページ幅やページ長の引数を利用します。また、 課金用のエントリを作成するため、ログイン名、ホスト名、 課金ファイル名の引数を利用します。

もし、フィルタの購入を検討しているならば、LPD と互換性があるかどうかを確認してください。もしそうならば、 上述の引数リストをサポートしていなければなりません。 一般向けの使用のためにフィルタを作成する計画をしている場合は、 同じ引数リストと終了コードをサポートしてください。

9.4.1.2. プレインテキストのジョブを PostScript® プリンタで印字する

コンピュータと PostScript (または、他の言語に対応した) プリンタをあなたしか使用しない場合は、プリンタにプレ インテキストを絶対に送らない、そして、 プリンタにプレインテキストを送りたがっている 様々なプログラムの機能を決して使わないことにしてください。そうすれば、 この節に書かれたことに心を煩わせる必要はまったくなくなります。

しかし、PostScript とプレインテキストの両方のジョブをプリンタへ送りたいと思っている場合は、 プリンタ設定についての要求が増えるでしょう。 両者をプリンタへ送信するためには、 到着したジョブがプレインテキストであるか PostScript であるかを検出するテキストフィルタが必要です。 PostScript のジョブはすべて %! で始まらなければならないことになっています (他のプリンタ言語に関しては、 プリンタのドキュメントをご覧ください)。 ジョブの最初の 2 文字がこれならば、PostScript であることが分かります。 したがって、 ジョブのそれ以降の部分をプリンタに直接送ることができます (訳注: PostScript では、% 以降はコメントとして扱われるので、最初の %! の行を読み捨てても問題はない)。 最初の2文字が %! でない場合は、 フィルタはテキストを PostScript に変換し、 その結果を使って印字をおこないます。

この作業をどうやってやればよいのでしょうか。

シリアルポートにプリンタを接続した場合は、 lprps をインストールすることをお勧めします。 lprpsPostScript 用のフィルタで、 プリンタとの双方向通信をおこないます。 このフィルタでは、プリンタからの冗長な情報を得ることで、 プリンタの状況を示すファイルが更新されていきます。 したがって、ユーザや管理者は (“トナー残量少”や “紙詰まり”といった) プリンタの状況を正確に知ることができます。しかし、 もっと重要なことは、psif と呼ばれるプログラムが含まれているということです。 このプログラムは、 入力されたジョブがプレインテキストかどうかを検出し、 これを PostScript に変換するために、textps (lprps に付属する別のプログラム) を呼び出します。そして、このジョブをプリンタに送るために、 lprps が使われます。

lprps は FreeBSD Ports Collection に含まれています (Ports Collection を参照してください)。 もちろん、自分自身でプログラムを取ってきて、コンパイルし、 インストールすることもできます。lprps をインストールした後は、lprps の一部である psif プログラムのパス名を指定するだけです。Ports Collection から lprps をインストールしたときは、 /etc/printcap の中のシリアル接続した PostScript プリンタのエントリに対して、次を使ってください。

:if=/usr/local/libexec/psif:

LPD にプリンタをリード・ライトモードでオープンさせるために、 rw 項目も指定すべきです。

パラレルポート接続の PostScript プリンタの場合 (すなわち、 lprps が 必要としているプリンタとの双方向通信ができない)、 テキストフィルタとして次のシェルスクリプトを使うことができます。

#!/bin/sh
#
#  psif - Print PostScript or plain text on a PostScript printer
#  Script version; NOT the version that comes with lprps
#  Installed in /usr/local/libexec/psif
#

IFS="" read -r first_line
first_two_chars=`expr "$first_line" : '\(..\)'`

if [ "$first_two_chars" = "%!" ]; then
   #
   #  PostScript job, print it.
   #
   echo "$first_line" && cat && printf "\004" && exit 0
   exit 2
else
   #
   #  Plain text, convert it, then print it.
   #
   ( echo "$first_line"; cat ) | /usr/local/bin/textps && printf "\004" && exit 0
   exit 2
fi

上記のスクリプトにおいて、textps はプレインテキストから PostScript へ変換するために別にインストールしたプログラムです。 テキストから PostScript へ変換するのには、 お好みのどんなプログラムでも使うことができます。FreeBSD Ports Collection (Ports Collection を参照してください) には、a2ps と呼ばれるテキストから PostScript に変換するプログラムが入っています。

9.4.1.3. 非 PostScript プリンタによる PostScript のシミュレート

PostScript は質の高い組版と印字をおこなうための 事実上の標準です。しかしながら、PostScript は、高価な標準です。ありがたいことに、 Aladdin Enterprises から Ghostscript と呼ばれる、 PostScript 互換の動作をするフリーのプログラムが出されていて、 FreeBSD で動きます。 Ghostscript はほとんどの PostScript ファイルを読むことができ、 これらの各ページを多くのブランドの非 PostScript プリンタを含む 様々なデバイス用に変換することができます。 Ghostscript をインストールし、 プリンタ用の特別なテキストフィルタを使うことによって、 非 PostScript プリンタをあたかも本物の PostScript プリンタであるかのように動作させることができます。

Ghostscript は FreeBSD Ports Collection に入っていますので、 そこからインストールすることができます。また、 自分でソースプログラムを持ってきて、コンパイルし、インストー ルすることもできます。この作業はとても簡単にできます。

PostScript プリンタをシミュレートさせる場合は、 テキストフィルタに PostScript ファイルを印字しようとしているかどうかを検出させます。 PostScript ファイルでない場合は、 フィルタはそのファイルを直接プリンタに送ります (訳注: テキストファイルを直接印字できない場合は、もちろん、 変換フィルタを通す必要があります)。PostScript の場合は、 まず、Ghostscript を使い、 ファイルをそのプリンタが理解できる形式へ変換します。

次の例のスクリプトは、Hewlett Packard DeskJet 500 プリンタ用 のテキストフィルタです。 他のプリンタで用いるときは、-sDEVICE 引数を gs (Ghostscript) コマンドに変えてください (gs -h と入力すると、現在インストールされている Ghostscript でサポートされているデバイスのリストが得られます)。

#!/bin/sh
#
#  ifhp - Print Ghostscript-simulated PostScript on a DeskJet 500
#  Installed in /usr/local/libexec/ifhp

#
#  Treat LF as CR+LF:
#
printf "\033&k2G" || exit 2

#
#  Read first two characters of the file
#
IFS="" read -r first_line
first_two_chars=`expr "$first_line" : '\(..\)'`

if [ "$first_two_chars" = "%!" ]; then
    #
    #  It is PostScript; use Ghostscript to scan-convert and print it.
    #
    #  Note that PostScript files are actually interpreted programs,
    #  and those programs are allowed to write to stdout, which will
    #  mess up the printed output.  So, we redirect stdout to stderr
    #  and then make descriptor 3 go to stdout, and have Ghostscript
    #  write its output there.  Exercise for the clever reader:
    #  capture the stderr output from Ghostscript and mail it back to
    #  the user originating the print job.
    #
    exec 3>&1 1>&2
    /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \
        -sOutputFile=/dev/fd/3 - && exit 0

else
    #
    #  Plain text or HP/PCL, so just print it directly; print a form feed
    #  at the end to eject the last page.
    #
    echo "$first_line" && cat && printf "\033&l0H" && 
    exit 0
fi

exit 2

最後に、if 項目を通して、LPD にこのフィルタを教えてやる必要があります。

:if=/usr/local/libexec/ifhp:

これでおしまいです。lpr plain.text とか lpr whatever.ps と入力してみましょう。どちらも正常に印字されるはずです。

訳注: 日本語を印字する場合は、 日本語対応の Ghostscript が必要です。日本語対応版の Ghostscript も Ports Collection に入っています。

9.4.1.4. 変換フィルタ

プリンタ設定導入編」 に書かれた簡単な設定が完了したら、最初に、 やってみたいと思うことは、多分 (プレイン ASCII テキストに加えて) 好みのファイル形式のための変換フィルタをインストールすることでしょう。

9.4.1.4.1. なぜ、変換フィルタをインストールするのか?

変換フィルタによって、 様々な種類のファイルを印字することが簡単になります。たとえば、TeX 組版システムでたくさんの仕事をしたと仮定しましょう。 そして、PostScript プリンタが接続 されているとします。 すると、TeX で DVI ファイルを作成する度に、DVI ファイルを印字するために、 これを PostScript ファイルに変換する必要があります。 このコマンドは次のようになるでしょう。

% dvips seaweed-analysis.dvi
% lpr seaweed-analysis.ps

DVI ファイル用の変換フィルタがインストールしてあると、 LPD に変換を肩代わりさせることで毎回毎回 おこなわなければならなかった面倒な変換作業を省くことができます。 つまり、DVI を生成したら、 次のようなコマンドを入力するだけで、これが印字されます。

% lpr -d seaweed-analysis.dvi

LPD に DVI ファイルの変換をさせるためには、 -d オプション を指定します。 変換オプションのリストは「 整形と変換に関するオプション」 に載せてあります。

変化のオプションのそれぞれをプリンタに サポートさせるためには、 変換フィルタをインストールし、 そのパス名を /etc/printcap の中で指定しなくてはなりません。変換フィルタは、 プレインテキストを印字する代わりに、フィルタはファイルを プリンタが理解できる形式に変換するところを除けば、 「プリンタの簡単な設定」で説明したテキストファイル (「 テキストフィルタのインストール」 を見て下さい) に似ています。

9.4.1.4.2. どの変換フィルタをインストールすべきか?

使いたいと思う変換フィルタをインストールすべきです。 DVI のデータを頻繁に印字するならば、DVI 変換フィルタ をインストールするのが適切でしょう。印字しなくてはなら ない troff を大量に抱えている場合は、多分、 troff フィルタが欲しくなるはずです。

次の表は、LPD で動作するフィルタと、 /etc/printcap ファイルでのエントリする項目、そして、 lpr コマンドで呼び出す方法をまとめたものです。

ファイル形式 /etc/printcap項目 lpr オプション
cifplot cf -c
DVI df -d
plot gf -g
ditroff nf -n
FORTRAN text rf -f
troff tf -f
raster vf -v
プレインテキスト if なし、-p、または -l

先の例のように、lpr -d を使うためには、出力先のプリンタの /etc/printcap 内のエントリで、 df 項目が必要であることが分かります。

反論はあるかも知れませんが、FORTRAN テキストや plot のような形式は、多分、廃れてていくでしょう。 あなたのサイトで、自前のフィルタをインストールするだけで、 プリントオプションのいくつか、あるいは、 全部に新しい意味を与えることができます。たとえば、 Printerleaf ファイル (Interleaf デスクトップパブリッシングプログラムによるファイル) を直接印字したいとします。 そして、Printerleaf 用の変換フィルタを gf 項目で 指定したパスにインストールすれば、lpr -g の意味は “Printerleaf ファイルを印字する” 意味だとユーザに教えることができます。

9.4.1.4.3. 変換フィルタのインストール

変換フィルタは FreeBSD の基本システムのインストールとは別にインストールするプログラムなので、 変換フィルタは、 /usr/local ディレクトリの下に置くべきでしょう。 フィルタは LPD だけが実行する特別なプログラム、 すなわち、一般ユーザが実行する必要すらないプログラムなので、 /usr/local/libexec ディレクトリに置くのが普通です。

変換フィルタを使用可能にするためには、 /etc/printcap の目的のプリンタの適切な項目に フィルタがあるパス名を指定します。

DVI 変換フィルタをプリンタ bamboo のエントリに加えてみましょう。プリンタ bamboodf 項目を新たに加えた /etc/printcap ファイルの例を以下に再掲します。

#
#  /etc/printcap for host rose - added df filter for bamboo
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
        :sh:sd=/var/spool/lpd/rattan:\
        :lp=/dev/lpt0:\
        :if=/usr/local/libexec/if-simple:

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
        :sh:sd=/var/spool/lpd/bamboo:\
        :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:

DVI フィルタは /usr/local/libexec/psdf という 名前のシェルスクリプトです。 このスクリプトは次のようになっています。

#!/bin/sh
#
#  psdf - DVI to PostScript printer filter
#  Installed in /usr/local/libexec/psdf
#
#  Invoked by lpd when user runs lpr -d
#
exec /usr/local/bin/dvips -f | /usr/local/libexec/lprps "$@"

このスクリプトでは、dvips をフィルタモード (引数 -f) で、 標準入力上で起動しています。標準入力は印字するジョブです。 それから、PostScript プリンタ用フィルタ lprps (これについては「 プレインテキストのジョブを PostScript プリンタで印字する」 を参照してください) を LPD に与えられた引数を付けて起動します。 lprps はこれらの引数を印字されたページ分の課金をおこなうために使われます。

9.4.1.4.4. 変換フィルタのその他の例

変換フィルタのインストールには決まったステップがないので、 その代わりに、例をもっと挙げることにします。 これを自分でフィルタを作る際のガイドにしてください。 適当な例があったら、それをそのまま使ってください。

次のスクリプト例は、Hewlett Packard LaserJet III-Si のための、raster (ええと・・実は、GIF ファイル) 用の変換フィルタです。

#!/bin/sh
#
#  hpvf - Convert GIF files into HP/PCL, then print
#  Installed in /usr/local/libexec/hpvf

PATH=/usr/X11R6/bin:$PATH; export PATH

giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \
    && exit 0 \
    || exit 2

ここでは、GIF ファイルから PNM (portable anymap) 形式に変換し、次に PGM (portable graymap) 形式に変換してから、 LaserJet/PCL-互換データに変換しています。

上記のフィルタを使うプリンタのためのエントリを付け加えた /etc/printcap ファイルは次のようになります。

#
#  /etc/printcap for host orchid
#
teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
        :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\
        :if=/usr/local/libexec/hpif:\
        :vf=/usr/local/libexec/hpvf:

次のスクリプトは、PostScript プリンタ bamboo のための groff 組版システムの troff データのための変換フィルタです。

#!/bin/sh
#
#  pstf - Convert groff's troff data into PS, then print.
#  Installed in /usr/local/libexec/pstf
#
exec grops | /usr/local/libexec/lprps "$@"

上記のスクリプトではプリンタとの通信をおこなうため、 lprps をまた利用しています。 プリンタがパラレルポートに接続されている場合は、代わりに、 次のスクリプトを使うかもしれません。

#!/bin/sh
#
#  pstf - Convert groff's troff data into PS, then print.
#  Installed in /usr/local/libexec/pstf
#
exec grops

これで完成しました。次に、フィルタを使用可能にするため に /etc/printcap に加える必要があるエントリを示します。

:tf=/usr/local/libexec/pstf:

次の例をみたら、FORTRAN のベテランは赤面するかもしれません。 この FORTRAN テキストフィルタは、 プレインテキストを直接印字できるすべてのプリンタで利用できます。 このフィルタをプリンタ teak にインストールすることにしましょう。

#!/bin/sh
#
# hprf - FORTRAN text filter for LaserJet 3si:
# Installed in /usr/local/libexec/hprf
#

printf "\033&k2G" && fpr && printf "\033&l0H" && exit 0
exit 2

そして、このフィルタを使用可能にするため、以下の行を /etc/printcap のプリンタ teak のエントリに加えます。

:rf=/usr/local/libexec/hprf:

これが最後の、そして、若干複雑な例です。前に紹介した LaserJet プリンタ teak に、DVI フィルタを加える ことにしましょう。最初に、 簡単な部分をおこないます。すなわち、DVI フィルタの位置を /etc/printcap に書き加えます。

:df=/usr/local/libexec/hpdf:

さて、難しい部分であるフィルタの作成をおこないます。 このために、DVI から LaserJet/PCL への変換プログラムが必要です。FreeBSD の Ports Collection (Ports Collection を参照してください) には、それがあります。 dvi2xx というのがそのパッケージの名前です。 これをインストールすると、必要なプログラム dvilj2p が使えます。このプログラムは DVI を LaserJet IIp、LaserJet III、そして LaserJet 2000 の互換コードへ変換してくれます。

dvilj2p はフィルタ hpdf を極めて複雑にしています。 なぜなら、dvilj2p は標準入力からデータを読み込むことができないからです。 このプログラムを働かせるためには、ファイル名が必要です。 もっと悪いことに、ファイル名は .dvi で終わっている必要があり、標準入力の代わりに、 /dev/fd/0 を使うのは問題があります。 この問題は、(.dvi で終わる) 一時的なファイル名から/dev/fd/0 に (シンボリックな) リンクを張る ことで回避することができます。これで、 dvilj2p に強制的に標準入力からデータを読み込ませることができます。

もう1つの問題は、一時的なリンクを張るために /tmp ディレクトリを使うことができないという事実です。 シンボリックリンクはユーザ、グループが bin であるユーザに所有されています。フィルタはユーザ daemon として起動します。そして、 /tmp ディレクトリはスティッキービットが立っています。 フィルタはリンクを作ることができます。しかし、 リンクは別のユーザに所有されているため、 作業が終了したとき、このリンクを削除することができません。

その代わりに、シンボリックリンクは現在の作業ディレクトリ、 すなわち、スプーリングディレクトリ (/etc/printcapsd 項目で指定する) に作ることにします。 フィルタが作業するにはここの場所は完璧な場所で、なぜなら、 特に、スプーリングディレクトリのディ スクの空き容量は (ときどき) /tmp ディレクトリよりもたくさんあるからです。

以下に示すのが最後のフィルタです。

#!/bin/sh
#
#  hpdf - Print DVI data on HP/PCL printer
#  Installed in /usr/local/libexec/hpdf

PATH=/usr/local/bin:$PATH; export PATH

#
#  Define a function to clean up our temporary files.  These exist
#  in the current directory, which will be the spooling directory
#  for the printer.
#
cleanup() {
   rm -f hpdf$$.dvi
}

#
#  Define a function to handle fatal errors: print the given message
#  and exit 2.  Exiting with 2 tells LPD to do not try to reprint the
#  job.
#
fatal() {
    echo "$@" 1>&2
    cleanup
    exit 2
}

#
#  If user removes the job, LPD will send SIGINT, so trap SIGINT
#  (and a few other signals) to clean up after ourselves.
#
trap cleanup 1 2 15

#
#  Make sure we are not colliding with any existing files.
#
cleanup

#
#  Link the DVI input file to standard input (the file to print).
#
ln -s /dev/fd/0 hpdf$$.dvi || fatal "Cannot symlink /dev/fd/0"

#
#  Make LF = CR+LF
#
printf "\033&k2G" || fatal "Cannot initialize printer"

#
#  Convert and print.  Return value from dvilj2p does not seem to be
#  reliable, so we ignore it.

#
dvilj2p -M1 -q -e- dfhp$$.dvi

#
#  Clean up and exit
#
cleanup
exit 0

9.4.1.4.5. 自動変換: その他の変換フィルタ

ここまでに述べてきたフィルタによって、 印字環境の能率が上がったことと思います。しかし、 これはどのフィルタを使うかを (lpr(1) のコマンドライン上で) ユーザが指定しなくてはならないという代価を支払って実現されています。 コンピュータの事情にあまり詳しくないユーザにとって、 フィルタのオプションを指定させられるということは いらいらさせられるものになるでしょう。更に悪いことに、 間違ったフィルタオプションを指定されると、 間違った形式のファイルがそのフィルタに適用されることになり、 その結果、何百枚もの紙を吐き出すことになるかもしれません。

そのような結果になるならば、 変換フィルタをインストールするよりもむしろ、 テキストフィルタ (これがデフォルトフィルタなので) に印字するよう要求されたファイルの形式を検出させ、自動的に、 適切な変換フィルタを起動するようにしたいと思うかもしれません。 ここでは file コマンドのようなツールを役立たせることができます。 もちろん、いくつかの ファイル形式の違いを見分けることは難しいことでしょう。 そして、もちろん、それらのファイルに対しては、 変換フィルタを提供するだけで済ますこともできるのです。

FreeBSD Ports Collection には、apsfilter と呼ばれる自動変換をおこなうテキストフィルタがあります。 このフィルタは プレインテキスト、PostScript、DVI ファイルを検出し、適当な変換をおこなった後、 データを印字することができます。

9.4.1.5. 出力フィルタ

LPD スプーリングシステムでは、 ここまでにまだ取り上げていないフィルタ形式、 出力フィルタをサポートしています。出力フィルタは、 テキストフィルタのように、 プレインテキストのみを印字するために意図されたものですが、 非常に簡単化されています。テキストフィルタを用いずに、 出力フィルタを使っている場合は、次のようになります。

  • LPD はジョブ中の各ファイルに一度ではなく、 ジョブ全体に対して一度だけ出力フィルタを起動します。

  • LPD は出力フィルタに対し、 ジョブ中のファイルの先頭や末尾を特定するための対策を 一切おこなっていません。

  • LPD はユーザのログイン名やホスト名をフィルタに渡しません。 したがって、課金の処理をおこなうことは考えていません。 実際、出力フィルタには、以下2つの引数しか与えられません。

    filter-name -wwidth -llength

    ここで、width は対象となるプリンタの pw 項目、 lengthpl 項目に指定された数です。

出力フィルタの簡便さに誘惑されてはいけません。もし、 ジョブ中のそれぞれのファイルに別のページ番号を付加しようとしても、 出力フィルタはうまく動作しないでしょう。 そのような動作を期待しているならば、 (入力フィルタとしても知られている) テキストフィルタを使ってください。 詳しくは、「 テキストフィルタのインストール」をご覧ください。 さらに、出力フィルタは、実のところ、 もっと複雑になっています。まず、 特殊なフラグ文字を検出するために、 フィルタに送られてくるバイトストリームを検査する必要があります。 また、LPD に代わって、 自分自身にシグナルを送らなければなりません。

しかしながら、ヘッダページの印字をおこないたくて、 エスケープシーケンスやヘッダページを印字できるようにするその他の初期化文字列を送信する必要がある場合は、 出力ファイルが必要です。 (しかし、 ヘッダページを要求したユーザに対して課金しようとするのもまた無駄なことです。 LPD は出力フィルタにユーザやホストの情報を渡しません)。

1 台のプリンタに対し、LPD では出力フィルタとテキストやその他のフィルタを両方使うことができます。 このような場合、LPD はヘッダページ (「 ヘッダページ」 を参照してください) だけを印字させるために、出力フィルタを起動させます。 それから LPD では、出力フィルタに 2 バイトの文字 (ASCII 031 の次に ASCII 001) を送ることで、 出力フィルタが自分自身を停止することを期待しています。 2 バイト (031, 001) が出力フィルタに送られたとき、 出力フィルタは自分自身にシグナル SIGSTOP を送ることによって停止するはずです。 LPD がその他のフィルタを動かし終わると、 出力フィルタにシグナル SIGCONT を送って、出力フィルタを再起動します。

出力フィルタがあり、 テキストフィルタがない場合、 LPD はプレインテキストジョブを扱う場合に、 出力フィルタを使います。前述したように、出力フィルタでは、 ジョブ中の各ファイルの間に FORM FEED 文字や紙を送る他の文字を入れることはしません。 この動作は多分、 あなたが求めているものとは異なっているでしょう。 ほとんどの場合において、テキストフィルタが必要なはずです。

プログラム lpf は、 テキストフィルタの項で既に紹介しましたが、 出力フィルタとしても動作させることができます。もし、 簡便で極悪な出力フィルタが必要で、かつ、 バイトストリームを検査したりシグナルを送るコードを書きたくないときには、 lpf をお試しください。 あるいは、プリントが要求する初期化コードを送るために、 lpf をシェルスクリプトに包んで使うこともできます。

9.4.1.6. テキストフィルタ lpf

プログラム /usr/libexec/lpr/lpf は、 FreeBSD の バイナリ配布に付属しているテキストフィルタ (入力フィルタ) で、出力を字下げしたり (lpr -i でジョブが入力さ れたとき)、 文字を未処理のままプリンタに送ったり (lpr -l でジョブが入力されたとき)、 ジョブ中のバックスペースやタブの印字位置を調節したり、 印字したページに対して課金したりすることができます。また、 このフィルタは出力フィルタとしても動作させることができます。

lpf は多くの印字環境において使用することに適しています。 このフィルタには、プリンタに初期化文字列を送る機能はありませんが、 必要とされる初期化をおこない、それから lpf を実行させるためのシェルスクリプトを作成するのはたやすいことです。

lpf に対して、 印字ページへの課金を正確におこなわせるためには、 /etc/printcap ファイルの中の pwpl の項目に正確な値を入れておく必要があります。これらの値は、 どのくらいの量のテキストがページにフィットするか、また、 ユーザのジョブが何ページあるのかを調べるために使われます。 プリンタの課金についての詳しい情報については、「 プリンタの利用に対する課金」をご覧ください。

9.4.2. ヘッダページ

あなたが管理するシステムのユーザが たくさんおり、 ユーザ全員が様々なプリンタを使用する場合、多分、 必要悪であるヘッダページを 印字させることを検討したいと思うかもしれません。

ヘッダページは、バナー とか バーストページ としても知られていますが、 出力されたジョブが誰によるものなのかを特定させる働きがあります。 印字結果の山の中において、 ユーザのジョブによって印字された本物のドキュメント部分よりも際立たせるために、 ヘッダページは、通常、多分、縁が装飾されている大きな太文字で印字されます。 ヘッダページにより、 ユーザは自分が出したジョブがどこにあるのかをすばやく見つけることができます。 ヘッダページの欠点は、明らかに、すべてのジョブに対して、 紙が 1 枚余分に印字されるということです。 この紙の有効期間は短く、2 〜 3 分も続きません。最終的に、 これらの紙は再利用紙入れの中かくずの山に入れられることでしょう (ヘッダページはジョブ中の各ファイル毎に印字されるのではなく、 ジョブ毎に印字されるということに注意してください。したがって、 紙の消費はそれほどひどくはないかもしれません)。

もし、 プリンタがプレインテキストを直接印字できるならば、LPD システムは印字物に対して自動的にヘッダページを付けることができます。 PostScript プリンタを使っている場合は、 ヘッダページを生成する外部プログラムが必要になります。これについては、 「PostScript プリンタでのヘッダページ」をご覧ください。

9.4.2.1. ヘッダページの印字を許可する

プリンタ設定導入編 」節では、/etc/printcap ファイルの sh (``suppress header'' : “ヘッダを供給しない” という意味) を指定して、 ヘッダページの印字を止めていました。 プリンタでのヘッダページの印字を許可するには、 sh 項目を取り除くだけでよいのです。

とても簡単そうに見えるけど、本当かな?

それは本当です。 プリンタに初期化文字列を送るための 出力フィルタを用意しなくてはならないかもしれません。次に、Hewlett Packard PCL 互換プリンタの例を挙げます。

#!/bin/sh
#
#  hpof - Output filter for Hewlett Packard PCL-compatible printers
#  Installed in /usr/local/libexec/hpof


printf "\033&k2G" || exit 2
exec /usr/libexec/lpr/lpf

of 項目に出力フィルタのパス名を指定してください。 詳細については、「出力フィルタ」節 をご覧ください。

次に、以前紹介したプリンタ teak のための /etc/printcap ファイルの例を示します。ここでは、 ヘッダページの印字を許可し、上記の出力フィルタを追加しました。

#
#  /etc/printcap for host orchid
#
teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
        :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\
        :if=/usr/local/libexec/hpif:\
        :vf=/usr/local/libexec/hpvf:\
        :of=/usr/local/libexec/hpof:

さて、ユーザが teak からジョブを印字させたとき、 それぞれのジョブ毎にヘッダページが印字されます。 もし、ユーザが印字物を探すのに時間を費やしたいと思うなら、 lpr -h によってジョブを入力することで、 ヘッダページの印字を止めることができます。 これ以外の lpr(1) のオプションについては、 「 ヘッダページ用オプション」節をご覧ください。

Note: LPD では、ヘッダページの最後に、 FORM FEED 文字が印字されます。 プリンタに紙排出をさせるために、別な文字、 もしくは、別な文字列が利用されている場合は、 /etc/printcap 中の ff 項目で指定することができます。

9.4.2.2. ヘッダページを制御する

ヘッダページの印字が許可されていると、LPD長いヘッダを作ります。これには、 紙全面に大きな文字でユーザ名、ホスト名、 ジョブ名が書かれています。次に、このヘッダページの例を示 します (kelly が ジョブ名 outline を rose というホストから印字 された場合)。

      k                   ll       ll
      k                    l        l
      k                    l        l
      k   k     eeee       l        l     y    y
      k  k     e    e      l        l     y    y
      k k      eeeeee      l        l     y    y
      kk k     e           l        l     y    y
      k   k    e    e      l        l     y   yy
      k    k    eeee      lll      lll     yyy y
                                               y
                                          y    y
                                           yyyy


                                   ll
                          t         l        i
                          t         l
       oooo    u    u   ttttt       l       ii     n nnn     eeee
      o    o   u    u     t         l        i     nn   n   e    e
      o    o   u    u     t         l        i     n    n   eeeeee
      o    o   u    u     t         l        i     n    n   e
      o    o   u   uu     t  t      l        i     n    n   e    e
       oooo     uuu u      tt      lll      iii    n    n    eeee









      r rrr     oooo     ssss     eeee
      rr   r   o    o   s    s   e    e
      r        o    o    ss      eeeeee
      r        o    o      ss    e
      r        o    o   s    s   e    e
      r         oooo     ssss     eeee







                                              Job:  outline
                                              Date: Sun Sep 17 11:04:58 1995

LPD はこのテキストの終わりに FORM FEED 文字を加えます ので、ジョブは新しいページから開始されます (ただし、 /etc/printcap で出力先のプリンタのエントリに sf (suppress form feeds) が指定されているときはこ の限りではありません)。

お望みならば、LPD短いヘッダページを出力させることもできます。 この場合は、 /etc/printcap ファイルの中で sb (short banner) を指定してください。 ヘッダページは次のようになります。

rose:kelly  Job: outline  Date: Sun Sep 17 11:07:51 1995

デフォルトでは、LPD はヘッダページを最初に印字し、次にジョブの印字をおこないます。 この順番を逆にするときは、 /etc/printcaphl (header last) を指定してください。

9.4.2.3. ヘッダページに対する課金

LPD に備わっているヘッダページ出力機能を使うと、 入力されたジョブに対して課金をおこなうことができても、 ヘッダページは無料で提供しなくてはならない、 という特有のやり方を強要されます。

なぜでしょうか。

出力フィルタは単なる外部プログラムなので、 課金をするための制御をおこなうとすれば、 それはヘッダページを印字するときですが、出力フィルタには、 ユーザ名とホスト名 の情報や課金情報を格納するファイルがどれな のかということが知らされません。それゆえ、出力ファイルには、 誰にプリンタ利用の課金をおこなえばよいのかが分からないのです。 テキストフィルタやその他の変換フィルタ (これらのフィルタはユーザやホストの情報が知らされます) が出力ページの枚数に “1ページ分水増しする” だけでは十分ではありません。 なぜなら、ユーザは lpr -h に よってヘッダページの出力を止めることができるからです。 やみくもに 1 ページを水増しすると、 印字されてもいないヘッダページに対する 料金をとることになります。基本的に、lpr -h は環境に優しい心を持つユーザに好まれるオプションですが、 これを使うように奨励することもできません。

各々のフィルタに独自のヘッダページを生成させる (その結果、ヘッダページに課金することができる) という方法でも十分であるとはいえません。 この場合、LPD はフィルタに -h の情報を送りませんので、lpr -h によってヘッダページを印字しないオプションを選択したとしても、 依然としてヘッダページは印字され、 その分の課金がおこなわれてしまいます。

では、どのような選択肢があるのでしょうか。

ヘッダページへの課金に関しては、 次のことができます。

  • LPD のやり方を受け入れ、 ヘッダページは無料とする。

  • LPRng などの LPD の代替品をインストールする。 LPD と入れ替えが可能な他のスプーリングソフトウェアに関しては、 標準スプーラの代替品 をご覧ください。

  • スマートな 出力フィルタを作成する。通常、 出力フィルタはプリンタを初期化するか、 単純な文字列変換をする程度の働きしかしません。 (テキスト (入力) フィルタがない場合) 出力フィルタはヘッダページとプレインテキストの印字をおこなうのに適しています。 プレインテキストを印字するためのテキストフィルタがない場合、 LPD はヘッダページを印字するためだけの目的で出力フィルタを起動します。 そして、LPD が生成するヘッダページのテキストを解析することにより、 出力フィルタはヘッダページに課金するために必要なユーザ名と ホスト名を取得することができます。この方式の唯一の問題点は、 出力フィルタは課金情報を格納するデータファイルの名前を知ることが できないということです (af 項目で指定されたファイル名は 出力ファイルに渡されません)。しかし、既知の 名前の課金データファイルを使うのならば、 その名前を出力フィルタのプログラム中に埋め込むことができます。 解析の手順を簡単にするためには、 /etc/printcapsh 項目 (短いヘッダを指定) を使うとよいでしょう。 そしてまた、 ここまでの方法は少なからぬトラブルを生じさせるかもしれません。 そうなれば、もちろんユーザはヘッダページを無料で 提供してくれる気前のよいシステム管理者に感謝することでしょう。

9.4.2.4. PostScript プリンタでのヘッダページ

これまでに述べたように、LPD ではプレインテキストのヘッダページをたくさんのプリンタに合うように生成することができます。 残念ながら、PostScript プリンタは、 プレインテキストを直接印字することができません。ですから、 LPD のヘッダページ機能はまったく、 あるいはほとんどの場合、役に立ちません。

ヘッダページを出力するための自明な方法の1つに、 すべての変換フィルタとテキストフィルタにヘッダページを生成させる方法があります。 フィルタは、 適切なヘッダページを生成するために、 ユーザ名とホスト名の引数を使うべきです。この方法の欠点は、いつでも、 lpr -h によってジョブが入力された場合でさえも、 ヘッダページが印字されるということです。

この方法で試してみましょう。次のスクリプトは、3 つの引数 (ユーザ のログイン名、ホスト名、ジョブ名) をとり、簡単な PostScript 用 のヘッダページを生成します。

#!/bin/sh
#
#  make-ps-header - make a PostScript header page on stdout
#  Installed in /usr/local/libexec/make-ps-header
#

#
#  These are PostScript units (72 to the inch).  Modify for A4 or
#  whatever size paper you are using:
#
page_width=612
page_height=792
border=72

#
#  Check arguments
#
if [ $# -ne 3 ]; then
    echo "Usage: `basename $0` <user> <host> <job>" 1>&2
    exit 1
fi

#
#  Save these, mostly for readability in the PostScript, below.
#
user=$1
host=$2
job=$3
date=`date`

#
#  Send the PostScript code to stdout.
#
exec cat <<EOF
%!PS

%
%  Make sure we do not interfere with user's job that will follow
%
save

%
%  Make a thick, unpleasant border around the edge of the paper.
%
$border $border moveto
$page_width $border 2 mul sub 0 rlineto
0 $page_height $border 2 mul sub rlineto
currentscreen 3 -1 roll pop 100 3 1 roll setscreen
$border 2 mul $page_width sub 0 rlineto closepath
0.8 setgray 10 setlinewidth stroke 0 setgray

%
%  Display user's login name, nice and large and prominent
%
/Helvetica-Bold findfont 64 scalefont setfont
$page_width ($user) stringwidth pop sub 2 div $page_height 200 sub moveto
($user) show

%
%  Now show the boring particulars
%
/Helvetica findfont 14 scalefont setfont
/y 200 def
[ (Job:) (Host:) (Date:) ] {
200 y moveto show /y y 18 sub def
} forall

/Helvetica-Bold findfont 14 scalefont setfont
/y 200 def
[ ($job) ($host) ($date) ] {
        270 y moveto show /y y 18 sub def
} forall

%
%  That is it
%
restore
showpage
EOF

そして、変換フィルタやテキストフィルタがそれぞれ、 最初にこのスクリプトを起動することで、 ヘッダページが出力され、それから、 ユーザのジョブの印字をおこないます。次に、 このドキュメントの始めのほうで紹介した DVI 変換フィルタを、 ヘッダページを印字するように変更したものを示します。

#!/bin/sh
#
#  psdf - DVI to PostScript printer filter
#  Installed in /usr/local/libexec/psdf
#
#  Invoked by lpd when user runs lpr -d
#

orig_args="$@"

fail() {
    echo "$@" 1>&2
    exit 2
}

while getopts "x:y:n:h:" option; do
    case $option in
        x|y)  ;; # Ignore
        n)    login=$OPTARG ;;
        h)    host=$OPTARG ;;
        *)    echo "LPD started `basename $0` wrong." 1>&2
              exit 2
              ;;
    esac
done

[ "$login" ] || fail "No login name"
[ "$host" ] || fail "No host name"

( /usr/local/libexec/make-ps-header $login $host "DVI File"
  /usr/local/bin/dvips -f ) | eval /usr/local/libexec/lprps $orig_args

このフィルタがユーザ名やホスト名を決定するために 引数リストをどのように解析しなくてはならないかという点に注意してください。 この解析方法は他の変換フィルタに対しても同様です。 しかしながら、テキストフィルタについては、 引数の設定が少し異なっています (これについては、「 フィルタはどのように機能しているか」 をご覧ください)。

前述の通り、上記の手法は、極めて単純なのにも関らず、 lpr で “ヘッダページを印字しない” オプション (-h オプション) が使えなくなっています。 ユーザが森林資源を (あるいは、 ヘッダページが課金されているならば、その僅かな金額を)、 節約したいと望んでいる場合でも、 すべてのフィルタがすべてのジョブ毎にヘッダページを印字 することになっているので、節約することはできません。

ジョブ毎に印字されるヘッダページを ユーザが抑制できるようにするためには、「 ヘッダページに対する課金」で紹介したトリックを 使う必要があります。すなわち、LPD が生成するヘッダページの解析をおこない、PostScript 版のヘッダページを出力させる出力フィルタを作るのです。 この場合、ユーザが lpr -h でジョブを入力すると、 LPD はヘッダページを生成しなくなり、また、 出力フィルタも起動されません。そうでないならば、 作成した出力フィルタが LPD からのテキストを読み込み、ヘッダページを印字する適当な PostScript のコードがプリンタに送られるでしょう。

PostScript プリンタがシリアルポートに接続されている場合、 出力フィルタとして lprps を、 上記の動作をおこなうものとして psof を使うことができます。ただし、psof はヘッダページに対して課金をおこないませんので注意してください。

9.4.3. リモートプリンタからの出力

FreeBSD では、ネットワーク越しの印字、すなわち、 ジョブをリモートプリンタに送ることをサポートしています。 リモートプリンタからの出力をするには、一般に、 次の 2 つを参照してください。

9.4.3.1. リモートホストに接続されたプリンタ

LPD スプーリングシステムでは LPD (または LPD 互換のシステム) が起動している他のホストへジョブを送る機能が 始めからサポートされています。この機能により、 あるホストに接続されたプリンタへ、 他のホストからアクセスできるようになります。また、 LPD プロトコルを理解するネットワークインタフェースを持ったプリンタに対しても、 この機能は働きます。

リモートプリンタへの出力を許可するためには、最初に、 あるホスト (これを、 プリンタホストと呼びます) にプリンタを接続します。そして、「 プリンタ設定導入編」 に書かれた簡単なプリンタの設定をおこなってください。 必要ならば、「プリンタ設定上級編」 にある、更に進んだ設定をおこなってください。そして、 そのプリンタをテストしてうまく動作することを確認し、LPD に許可した機能がうまく働くかどうかを見てください。さらに ローカルホストプリンタホストLPD サービスの使用を許可されているか確認して下さい (「 リモートホストからのプリンタの利用を制限する 」参照)。

LPD 互換のネットワークインタフェースを持つプリンタを使用している場合は、 そのプリンタ自身が以下で説明する プリンタホストになります。そして、 プリンタ名とは、 そのプリンタに設定した名前のことを指します。 これについては、プリンタ、および (または)、 プリンタのネットワークインタフェースに付属するドキュメントを参照してください。

Tip: ヒューレット・パッカード社の Laserjet シリーズを使用している場合には、 プリンタ名を text とすると、 自動的に LF から CRLF への変換が行なわれます。 そのため、hpif スクリプトは必要ありません。

次に、 そのプリンタにアクセスしたいと思っている他ホストにおいて、 そのホストの /etc/printcap ファイルに次にあげるエントリを作ります。

  1. 名前のエントリ。どんな名前でもよいのですが、簡単のため、多分、 プリンタホストで設定されたプリンタ名や別名と同じものを使いたいと思うでしょう。

  2. lp 項目で指定されるデバイスは明示的に空にします (:lp=: とします)。

  3. スプーリングディレクトリを作成し、 sd 項目でその位置を指定します。 LPD では、プリンタホストにジョブを送信するまでの間、 このディレクトリにジョブを格納します。

  4. rm 項目でプリンタホストの名前を指定します。

  5. rp 項目で プリンタホストに接続したプリンタ名を指定します。

これで終わりです。 変換フィルタやページの大きさやその他の事項を /etc/printcap に加える必要はありません。

次に、 リモートホストに接続されたプリンタで印字するための設定例を示します。 ホスト rose には 2 台のプリンタ bamboorattan が接続されています。これらのプリンタをホスト orchid のユーザが使えるようにしましょう。最初に orchid/etc/printcap を示します (このファイルは、「 ヘッダページの出力を許可する」 で参照することができます)。このファイルには、既に、プリンタ teak 用のエントリがありました。以下では、 これに、ホスト rose にある2台のプリンタ用のエントリが加えられています。

#
#  /etc/printcap for host orchid - added (remote) printers on rose
#

#
#  teak is local; it is connected directly to orchid:
#
teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
        :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\
        :if=/usr/local/libexec/ifhp:\
        :vf=/usr/local/libexec/vfhp:\
        :of=/usr/local/libexec/ofhp:

#
#  rattan is connected to rose; send jobs for rattan to rose:
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
        :lp=:rm=rose:rp=rattan:sd=/var/spool/lpd/rattan:

#
#  bamboo is connected to rose as well:
#
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
        :lp=:rm=rose:rp=bamboo:sd=/var/spool/lpd/bamboo:

orchid で必要となる作業はスプーリングディレクトリを作ることだけです。

# mkdir -p /var/spool/lpd/rattan /var/spool/lpd/bamboo
# chmod 770 /var/spool/lpd/rattan /var/spool/lpd/bamboo
# chown daemon:daemon /var/spool/lpd/rattan /var/spool/lpd/bamboo

これで、orchid のユーザが rattanbamboo で印字することができるようになりました。 たとえば、orchid のユーザが次のように入力したとします。

% lpr -P bamboo -d sushi-review.dvi
すると、orchidLPD システムは、 ジョブをスプーリングディレクトリ /var/spool/lpd/bamboo にコピーし、これが DVI ファイルを印字するジョブであることを記録します。 ホスト rosebamboo スプーリングディレクトリに十分な容量が確保でき次第、 両者の LPD は、ジョブのファイルを rose に転送します。 このファイルは、そのすべてが印字されるまで、rose のキューに留まります。 (bambooPostScript プリンタなので) DVI から PostScript への変換は rose でおこなわれます。

9.4.3.2. ネットワークにおけるデータストリームの インタフェースを持つプリンタ

プリンタのネットワークインタフェースカードは、 2 種類に分類することができます。 1 つはスプーラをエミュレートするもの (高価) で、もう 1 つはシリアルやパラレルポートを使うように プリンタにデータを送ることができるだけのもの (安価) です。この節では、 後者の使い方を説明します。前者のプリンタは、前節「 リモートホストに接続されたプリンタ」 の方法が適用できます。

/etc/printcap ファイルでは、 シリアルかパラレルのインタフェースのどちらを使うのか、 そして、(シリアルインタフェースを使う場合) そのボーレートはいくらであるか、フロー制御は使うのか、 タブのための遅延を加えるのか、 改行文字を変換するかなどの指定をおこなうことができます。 しかし、TCP/IP や他のネットワークポートからデータを受け取るプリンタを 接続するための指定をおこなうことはでき ません。

ネットワーク接続されたプリンタにデータを送るためには、 テキストフィルタと変換フィルタから呼び出すことができる 通信プログラムを開発する必要があります。以下に、 そのようなプログラムの例を示します。スクリプト netprint では、 標準入力から印字データをすべて受け取り、 ネットワーク接続されたプリンタにこれを送ります。 netprint の最初の引数でプリンタのホスト名を、 2 番目の引数で接続するポート番号を指定します。 このプログラムでは単方向通信 (FreeBSD からプリンタ) のみをサポートしていることに注意してください。 ネットワークプリンタの多くは双方向通信をサポートしていますので、 その恩恵 (プリンタの状態を得たり、 課金をおこなうなど) にあずかりたいと思われるかもしれません。

#!/usr/bin/perl
#
#  netprint - Text filter for printer attached to network
#  Installed in /usr/local/libexec/netprint
#

$#ARGV eq 1 || die "Usage: $0 <printer-hostname> <port-number>";

$printer_host = $ARGV[0];
$printer_port = $ARGV[1];

require 'sys/socket.ph';

($ignore, $ignore, $protocol) = getprotobyname('tcp');
($ignore, $ignore, $ignore, $ignore, $address)
    = gethostbyname($printer_host);

$sockaddr = pack('S n a4 x8', &AF_INET, $printer_port, $address);

socket(PRINTER, &PF_INET, &SOCK_STREAM, $protocol)
    || die "Can't create TCP/IP stream socket: $!";
connect(PRINTER, $sockaddr) || die "Can't contact $printer_host: $!";
while (<STDIN>) { print PRINTER; }
exit 0;

このスクリプトは、 様々なフィルタが利用することができます。仮に、Diablo 750-N ラインプリンタを持っており、 これがネットワークに接続されているとしましょう。 プリンタはポート番号 5100 にて印字するデータを受け取ります。 プリンタのホスト名は scrivener とします。このとき、 このプリンタのテキストフィルタは次のようになります。

#!/bin/sh
#
#  diablo-if-net - Text filter for Diablo printer `scrivener' listening
#  on port 5100.  Installed in /usr/local/libexec/diablo-if-net
#

exec /usr/libexec/lpr/lpf "$@" | /usr/local/libexec/netprint scrivener 5100

9.4.4. プリンタの利用に制約を与える

本節では、プリンタの利用に制約を与えるための情報を記しています。 LPD システムでは、プリンタ (ローカル、 リモートのいずれに接続されていても) にアクセスできる人を制限する機能、 複数部のコピーの印字の可否を制御する機能、 ジョブのサイズの最大値やプリンタキューに入る ジョブの最大個数を制御する機能を提供しています。

9.4.4.1. 複数部のコピーの印字を制限する

LPD システムではユーザが複数部のコピーの印字を簡単におこなう 機能を提供しています。ユーザが、(たとえば) lpr -#5 コマンドを使ってジョブを印字すると、 ジョブのそれぞれのファイルのコピーを 5 部得ることができます。 これがよい機能であると思うかどうかは人それぞれでしょう。

複数部のコピーの印字によってプリンタが 必要以上に消耗してしまうと感じるならば、 /etc/printcap ファイルに sc 項目を加えてください。これにより、 lpr(1)-# オプションの使用が禁止されます。 このオプションが指定されているにも関らず、 -# オプションを使うと、 次のようなメッセージが表示され、 このオプションの利用できない旨を伝えます。

lpr: multiple copies are not allowed

リモートホストからプリンタをアクセスできる 設定にしている場合 (この 設定については、「 リモートホストに接続されたプリンタ」 をご覧ください)、そのリモートホストの /etc/printcap にも同じように sc 項目を追加する必要があることに注意してください。 そうしないと、ユーザは別なホストから複数部のコピーの 印字をすることができてしまいます。

例を使って説明しましょう。次に示す /etc/printcap ファイルは、ホスト rose のものです。プリンタ rattan は極めて頑丈なので、 複数部のコピーの印字は許可されています。しかし、 レーザプリンタの bamboo はもう少しデリケートで、 このプリンタから複数部のコピーを印字することを sc 項目を追加することで禁止しています。

#
#  /etc/printcap for host rose - restrict multiple copies on bamboo
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
        :sh:sd=/var/spool/lpd/rattan:\
        :lp=/dev/lpt0:\
        :if=/usr/local/libexec/if-simple:

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
        :sh:sd=/var/spool/lpd/bamboo:sc:\
        :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:

さらに、orchid の /etc/printcap にも

sc

項目を追加する必要があります (orchid でこの編集をおこなっているときに、ついでに、プリンタ teak でも複数部のコピーの印字を禁止することにしましょう)。

#
#  /etc/printcap for host orchid - no multiple copies for local
#  printer teak or remote printer bamboo

teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
        :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:sc:\
        :if=/usr/local/libexec/ifhp:\
        :vf=/usr/local/libexec/vfhp:\
        :of=/usr/local/libexec/ofhp:

rattan|line|diablo|lp|Diablo 630 Line Printer:\
        :lp=:rm=rose:rp=rattan:sd=/var/spool/lpd/rattan:

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
        :lp=:rm=rose:rp=bamboo:sd=/var/spool/lpd/bamboo:sc:

sc 項目を指定することにより、 lpr -# の使用を防ぐことができます。しかし、この状態では lpr(1) を複数回起動したり、 1 回のジョブで次のように同じファイルを複数個指定することを防ぐまでには至っていません。

% lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign

このような悪用を防ぐ方法は (その指示を無視することも含めて) たくさんあります。 各自で調べてみてください。

9.4.4.2. プリンタを使用できる人を限定する

それぞれのプリンタを使用できる人を限定するには、UNIX® の グループ権限のメカニズムを利用し、さらに、 /etc/printcaprg 項目を指定することでおこないます。 あるプリンタにアクセスさせてもよいと思うユーザすべてを グループのどれかに入れてください。そして、 そのグループ名を rg で指定します。

このとき、そのグループに含まれないユーザ (root も含みます) には、次のようなメッセージが表示され、プリンタの使用はできません。 “ lpr: Not a member of the restricted group

sc (suppress multiple copies : 複数部のコピーの印字を禁止する) を指定するときと同様に、rg が指定されたプリンタがリモートホストからもアクセスでき (この設定については、 「 リモートホストに接続されたプリンタ」 をご覧ください)、かつ、 そのホストでもプリンタを使用できる人を限定するのが 妥当であると思う場合は、 そのホストの /etc/printcap にも rg 指定をおこなう必要があります。

たとえば、プリンタ rattan は誰でも利用できるが、bamboo はグループ artists に属している人のみが利用できるようにしてみましょう。 以下に、もうお馴染みとなったホスト rose/etc/printcap を示します。

#
#  /etc/printcap for host rose - restricted group for bamboo
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
        :sh:sd=/var/spool/lpd/rattan:\
        :lp=/dev/lpt0:\
        :if=/usr/local/libexec/if-simple:

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
        :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:\
        :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:

これ以外の /etc/printcap ファイル (ホスト orchid のもの) はそのままにしておくことにします。もちろん、 orchid のユーザは全員 bamboo を利用することができます。これは、 orchid には特定のユーザのみにしかアクセスさせておらず、 そのユーザにはプリンタを利用させたいと思っているからなのかもしれませんし、 そうでないかもしれません。

Note: 1台のプリンタを複数グループのユーザに利用させることはできません。

9.4.4.3. 入力可能なジョブのサイズを制限する

たくさんのユーザからプリンタが利用される場合には、多分、 ユーザが印字要求を出すことができるファイルのサイズに 上限値を置く必要が生じるでしょう。結局のところ、 スプーリングディレクトリ が置かれているファイルシステムの空き容量がその 上限値になる訳ですが、 あるユーザがこれを独占的に使用すること避けるために、 他ユーザからのジョブ用の空き容量を確保する必要もあります。

LPD では、mx 項目を指定することにより、 ジョブ中の個々のファイルのサイズの上限値を制限する機能を提供しています。 指定される ファイルサイズの単位は BUFSIZ ブロックで、1 BUFSIZ ブロックは 1024バイトを表わします。この mx 項目の値として 0 が指定されると、 ファイルサイズの制限はなくなります。 mx が指定されない場合は、 デフォルトの制限として 1000 ブロックが使われます。

Note: この制限はジョブ中の各 ファイルに対して適用されるものであり、 ジョブ全体のサイズ を制限するものではありません

ところで、 プリンタに設定された上限値を超えるファイルサイズの ファイルが入力された場合でも、LPD はこれを拒否しません。その代わりに、このファイルは、 その先頭から上限値のファイルサイズまでしかキューに入れられません。 そして、その部分までが印字され、 残りの部分は捨てられます。 これが正しい動作といえるのかどうかは議論の余地があるところです。

それでは、設定例に登場しているプリンタ rattanbamboo の印字可能なファイルサイズに制限を加えてみましょう。artists グループの人達が作る PostScript ファイルのサイズは 巨大になる傾向があるので、上限値を 5M バイトとします。 それから、 プレインテキスト用のラインプリンタは無制限とします。

#
#  /etc/printcap for host rose
#

#
#  No limit on job size:
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
        :sh:mx#0:sd=/var/spool/lpd/rattan:\
        :lp=/dev/lpt0:\
        :if=/usr/local/libexec/if-simple:

#
#  Limit of five megabytes:
#
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
        :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\
        :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:

この場合もそうですが、この制限はローカル (ホスト rose) のユーザのみに適用されます。 リモートホストからプリンタを利用できるように設定している場合は、 そのリモートホストのユーザはこの制限を受けません。 これらのユーザにも制限を加える場合は、リモートホストの /etc/printcapmx を指定する必要があります。 リモートホストから印字するための詳しい情報については、 「 リモートホストに接続されたプリンタ」 を参照してください。

リモートホストに接続されたプリンタへのジョブの サイズを制限する特別な方法は他にもあります。これについては、 「 リモートホストからのプリンタの利用を制限する」 を参照してください。

9.4.4.4. リモートホストからのプリンタの利用を制限する

LPD スプーリングシステムでは、 リモートホストから要求されたジョブの印字を制限するための方法がいくつか提供されています。

ホストの制限

ローカルの LPD が印字要求を受け付けるリモートホストは、ファイル /etc/hosts.equiv/etc/hosts.lpd によって制御することができます。LPD では、あるホストから印字の要求がきたとき、 このホストの名前がこれら 2 つのファイルのどちらかに含まれている かどうかを調べます。これが含まれていない場合は、LPD はこの要求を拒否します。

これらのファイルの形式は単純です。 各行にホストの名前を 1つずつ書いていきます。ファイル /etc/hosts.equiv の方は ruserok(3) プロトコルでも利用され、 rsh(1)rcp(1) といったプログラムの動作に影響するので注意が必要です。 /etc/hosts.equiv の記述は慎重におこないましょう。

例として、以下にホスト rose/etc/hosts.lpd を示します。

orchid
violet
madrigal.fishbaum.de

この例では、rose はホスト orchid, violet そして madrigal.fishbaum.de からの要求を受け付けることになります。 その他のホストが roseLPD にアクセスしようとしても、 LPD はそのジョブを拒否します (訳注: 拒否されるのは、そのホストが /etc/hosts.equiv にも含まれていない場合です)。

サイズの制限

スプーリングディレクトリがある ファイルシステムに残しておく必要がある 空き容量の大きさを制御することができます。 ローカルプリンタ用のスプーリングディレクトリに minfree という名前のファイルを作成します。そして、 そのファイルの中にリモートホストからのジョブの 要求を受け付けるために必要な空き容量のディスクブロックサイズ (1 ディスクブロック = 512 バイト) を記します。

これで、 リモートホストのユーザにファイルシステムを満杯にされないことが保証されます。 この機能を使うと、 ローカルホストのユーザに対してある種の優先権を与えることもできます。 ローカルホストのユーザは、 minfree ファイルで指定された値よりもディスクの空き容量が下回った後でもずっと、 ジョブをキューに入れることができるのです。

たとえば、プリンタ bamboo 用の minfree を作ってみましょう。 このプリンタのスプーリングディレクトリを調べるために、 /etc/printcap を調べてみましょう。 以下に、bamboo のエントリ部分を示します。

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
        :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\
        :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:mx#5000:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:

スプーリングディレクトリは sd 項目で指定されます。LPD がリモートホストからのジョブを受け付けるために必要な ファイルシステムの空き容量を 3M バイト (= 6144 ディスクブロック) にすることにしましょう。

# echo 6144 > /var/spool/lpd/bamboo/minfree
             
利用ユーザの制限

/etc/printcaprs 項目を指定することで、 ローカルプリンタを利用できるリモートホストのユーザを制限することができます。 ローカルホストに接続されたプリンタ用のエントリに rs 項目が指定されている場合、 LPD は、印字を要求したユーザのアカウントと同じログイン名が ローカルホストに登録されている場合に限り、 そのジョブを受け付けます。それ以外のジョブを LPD は拒否します。

この機能は、(たとえば) 複数の部署がネットワークを共有しており、 この内のあるユーザが部署の境界を越えて活動している場合には特に有用です。 そのようなユーザに対して、システムのアカウントを与えるだけで、 これらのユーザは自分が所属する部署のシステムから そのシステムに接続されているプリンタを使用することができます。 これらのユーザにはむしろ、 プリンタの使用だけを認め、 その他のコンピュータ資源を利用させたくないときは、 それらのユーザにはホームディレクトリを与えず、 ログインシェルはシェルとしては何の役にも立たない /usr/bin/false などを指定して、 これらのユーザのアカウントはプリンタ用の “形式的な” ものとします。

9.4.5. プリンタの利用に対する課金

という訳で、印字するためには料金をとることが必要です。 取らない理由などありましょうか。紙やインクにはお金がかかります。 そして、プリンタの維持費もかかります。 プリンタには可動部分が搭載されており、 これらの部分は壊れやすいという傾向があります。 プリンタや、その利用形態、維持費について調査をし、1 ページ (1 フィート、1 メートルなど) 当たりにかかるコストを調べておいてください。 これに基づき、プリンタの利用に対する課金を、実際に、 どのように始めればよいのでしょうか。

さて、残念ながら、この部分に関しては LPD スプーリングシステムはほとんど役に立ちません。 課金は使用しているプリンタの種類、印字するもののファイルの形式、 プリンタの利用に対する課金での あなた自身の要求に大きく左右されます。

課金システムを実現するためには、プリンタのテキストフィルタ (プレインテキストのジョブに対して課金するため) と変換フィルタ (その他のファイル形式に対して課金するため) を変更して、 印字したページを数えたり、 プリンタに印字したページ数を取得するための要求を送る必要があります。 ただし、出力フィルタのみを利用している場合は、 課金をおこなうことができません。フィルタに関しては、 「 フィルタ」をご覧ください。

一般に、課金方式には次の 2 つがあります。

LPD スプーリングシステムでは、 どちらの方式にも簡単に対応できます。(ほとんどの場合は) フィルタを用意しなければならないので、 課金作業のためのコードも用意しなければなりません。 しかし、明るい面もあります。 それは、課金方式に関して、非常に大きな柔軟性が与えられたということです。 たとえば、「定期的に課金する方法」か、 「利用毎に課金する方法」のどちらかを選びまず、そして、 どんな情報 (ユーザ名、ホスト名、ジョブのタイプ、印字された頁数、 使用した紙の大きさ、印字をするために要した時間など) をログに記録するかを決めます。 以上のことをおこなうには、上記の情報を保持するために、 フィルタを変更しなくてはなりません。

9.4.5.1. 手軽なプリンタ課金方法

FreeBSD には、「定期的に課金する方法」による課金を すぐに設定できるように、2 個のプログラムを添付しています。 その内の1つはテキストフィルタ lpf で、 これについては、「 テキストフィルタ lpf」をご覧ください。もう1つは、 pac(8) で、 これはプリンタの課金データファイルからのエントリを集め、 これを合計するプログラムです。

フィルタはどのように機能しているか」で述べたように、 LPD ではテキストフィルタや変換フィルタを起動しますが、 そのコマンドラインで使用している課金データファイルの名前が指定されます。 両フィルタはこの引数を使って、 どの課金データファイルのエントリに書き込めばよいのかを知ることができます。 このファイルの名前は /etc/printcap 中の af 項目によって指定されます。 このファイルが絶対パ スで指定されない場合は、 スプーリングディレクトリからの相対パスとして扱われます。

LPD は、紙のページの幅と行数 (pwpl 項目で 指定される) を引数として lpf を起動します。lpf では、何ページ印字したかを決定するためにこれらの引数を使用します。 ファイルをプリンタに送った後、 課金情報を課金データファイルに書き込みます。 このファイルは次のようになります。

2.00 rose:andy
3.00 rose:kelly
3.00 orchid:mary
5.00 orchid:mary
2.00 orchid:zhang

課金データファイルはプリンタ毎に分けて作るべきです。 これは、lpf にはファイルをロックする機構が組み込まれていないためです。 したがって、lpf が 2 つ起動されたとき、 同じファイルに同時に書き込みをおこなった場合、 お互いのエントリを破壊してしまうかもしれません。 課金用ファイルを各プリンタ毎に確実に分けるには、 /etc/printcap 中の af=acct 項目を使います。 そうすれば、それぞれの課金用ファイルがプリンタのスプーリングディレクトリに、 acct という名称で作成されます。

プリンタの利用に対してユーザに課金する準備ができたら、 スプーリングディレクトリに移動した後、 pac(8) と入力してください。 次のような、ドル中心主義の課金リストが表示されます (訳注: ドル中心主義という表現は、 表示がドルで出ることへの著者の皮肉でしょう。 セントがあるので小数点以下が表示されますが、 この機能も日本では邪魔ですね)。

  Login               pages/feet   runs    price
orchid:kelly                5.00    1   $  0.10
orchid:mary                31.00    3   $  0.62
orchid:zhang                9.00    1   $  0.18
rose:andy                   2.00    1   $  0.04
rose:kelly                177.00  104   $  3.54
rose:mary                  87.00   32   $  1.74
rose:root                  26.00   12   $  0.52

total                     337.00  154   $  6.74

pac(8) が受け付ける引数には次のようなものがあります。

-Pprinter

プリンタ printer の利用に対する課金リストを作成します。 このオプションは、/etc/printcapaf が絶対パスで指定されていた場合に限り、動作します。

-c

ユーザ名のアルファベット順ではなく、 課金額の低い順にリストを並べます。

-m

課金データファイルにあるホスト名を無視します。 このオプションを使用すると、ホスト alpha のユーザ smith とホスト gamma のユーザ smith は同一人物として扱われます。 このオプションが指定されない場合は、 両者は別なユーザとして扱います。

-pprice

/etc/printcappc 項目で指定された値、または、 デフォルトの値 (2 セント) に代わり、紙1ページ、または、 1フィート当たりの価格を指定します。 price として、 浮動小数点数を指定することができます。

-r

リストの並べる順番を逆順にします。

-s

課金リストを作成し、 課金データファイルを削除します。

name ...

ユーザ names に対する課金情報のみを表示します。

pac(8) が生成するデフォルトのリストには、 各ホストのユーザ別に印字ページ数が表示されます。 (ユーザがサイト内のすべてのホストを使用できるため) ホスト名の情報が意味を持たない場合、 pac -m を実行してください。次のようなリストが得られます。

  Login               pages/feet   runs    price
andy                        2.00    1   $  0.04
kelly                     182.00  105   $  3.64
mary                      118.00   35   $  2.36
root                       26.00   12   $  0.52
zhang                       9.00    1   $  0.18

total                     337.00  154   $  6.74

課金額を決めるために、 pac(8)/etc/printcap ファイルの pc 項目で指定された値 (デフォルト値は 200、すなわち 1 ページ当たり 2 セント) を使います。この項目で、印字物に課金したい ファと思う 1 ページ当たり、 または、1 フィート当たりの価格を 100 分の 1 セント単位で指定します。 pac(8)-p オプション付きで起動すると、 この値を置き換えることができます。 この -p オプションで指定する額の単位は、 100 分の 1 セント単位ではなく、ドル単位です。たとえば、次の指定では、 1 ページ当たりの単価が 1 ドル 50 セントになります。

# pac -p1.50
このオプションを使うと、 実際の課金額を集計することができます。

最後に、pac -s を起動すると、課金情報は課金データ累計ファイルに保存されます。 このファイルの名前は、プリンタの課金データファイルの後ろに _sum を付けたものとなります。そして、 課金データファイルは削除されます。次に pac(8) が起動されると、 その時点までの累計金額を得るために、 課金データ累計ファイルが読み込まれ、 通常の課金データファイルからの情報に加算されます。

9.4.5.2. 印字されたページ数をどのように数えるか?

課金を、リモートホストからの印字でさえも、 正確におこなうためには、 ジョブで使用された紙が何ページであるかを特定できる必要があります。 このことは、プリンタ利用に対する課金をおこなう上の根本的な問題です。

プレインテキストのジョブの場合、 問題を解決するのはさほど難しくはありません。 ジョブが何行であったかを数え、プリンタがサポートしている紙 1 ページに印字できる最大の行数と比較すればよいのです。 重ね打ちするために利用されるファイル中のバックスペース文字や、 物理的に複数の行に渡る長い論理行に対する取り扱いを忘れずにおこなってください。

(「テキストフィルタ lpf」で紹介した) テキストフィルタ lpf では、課金をおこなうときに、 これらの取り扱いをおこなってくれます。 課金をおこなうために必要なテキストフィルタを作成している方は、 lpf のソースコードが参考になるでしょう。

これに対して、他のファイル形式の処理はどのようにすれば よいのでしょうか。

まず、DVI から LaserJet, または、DVI から PostScript への変換の場合、フィルタが dviljdvips の 出力メッセージを解析することで、 何ページ分の変換がおこなわれたかを知ることができます。 他のファイル形式とその変換プログラムに関しても、 同様のことができるかもしれません。

しかし、この方式には問題点があります。それは、 変換されたページがすべて印字されるとは限らないということです。 たとえば、プリンタが紙詰まりを起こしたり、トナー切れになったり、 はたまた、爆発したりするかもしれません。 そのような状況により印字が途中で中止されたとしても、この方式では、 ユーザは全ページ分の料金を課されてしまうのです。

それでは、どのような対策をたてることができるのでしょうか。

正確な 課金をおこなうための唯一の確実な方法は、 何ページ印字したのかを知らせることができるプリンタを入手し、 これをシリアルポートかネットワークに接続することです。 ほとんどすべての PostScript プリンタではこの概念がサポートされています。 他のプリンタも同様です (Imagen レーザプリンタをネットワーク接続するなど)。 それぞれのプリンタのフィルタを、 ジョブを印字した後で印字ページ数を得るように変更してください。 そして、課金情報はここで得られた値のみに 基づいて記録してください。行数を数えたり、 エラーが生じやすいファイルの調査は必要とされません。

もちろん、 気前よく印字料金をすべて無料にすることもできます。