CentOS6.xでlprコマンドを使って日本語のプレインテキストの綺麗な印刷

1.はじめに

CentOS6.x+日本語言語に選択した環境で標準設定のまま

> lpr `日本語のプレインテキスト.txt`

とするとあんまり綺麗に印刷してくれません。

ちょっとだけ綺麗にする方法について述べます。

CentOS6.xに入っているlprは実態はcupsです。なのでcupsの調整を行ないます。

なお、cupsの初期設定およびプリンタの追加の手順については省略しています。

日本語のプレインテキストが印刷できる環境は構築してから、本稿の続きを読んでください。

注意1： 本稿執筆にあたりPostscript言語対応のプリンタでしか動作確認してません。他のプリンタ言語のプリンタでは未確認です。

注意2: 追試が面倒なのでクリーンインストールの状態から試してません。作業に抜けがあるかも。

注意3: 面倒なので、cupsパッケージのバイナリファイルを直接差し替えています。yum update等でcupsのパッケージ更新があった場合、ファイルが挿し戻ってしまう可能性があります。印刷がうまくいかなくなったら作業をやり直して下さい。

2.プリンタ言語
世の中のプリンタは大抵、印刷用の言語を持ってます。パソコンでプリンタに印刷指示するときは印刷するファイルをプリンタの言語に変換して送ってるわけですね。

新しくプリンタ買った時はデバイスドライバのインストールしますが、あれはファイルをプリンタ用の言語に変換するためのもんなのですね。

代表的なプリンタ言語としてEPSONのESC/P, CanonのLIPS、アドビのPostscriptとかあります。

https://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AA%E3%83%B3%E3%82%BF%E3%83%BC#.E5.88.B6.E5.BE.A1.E6.96.B9.E5.BC.8F

伝統的にUNIX(Linux)ではPostscriptを主体にプリンタ関係のプログラムが設計されています。

ちなみにいにしえのNEC PC-9801あたりからの伝統で日本語が使えるプリンタや商用OSはPR201ってプリンタ言語を標準でサポートしていたりします。


3.プレインテキスト印刷時に使われるフィルタ

プレインテキスト印刷時に使われるフィルタですが、次のような処理になります。

(たぶん。違ったらごめんね。)

- lprでテキストファイルをcupsのdaemonに送信
- cups内蔵フィルタがテキストファイルをPostscriptに変換
- Postscriptを各プリンタ言語に変換(実態はGhostscriptなど。)
- プリンタに送信

で、今回の本題である綺麗な日本語のプレインテキストの綺麗な印刷ですが、上記の一連の処理で

- cups内蔵フィルタがテキストファイルをPostscriptに変換

この処理に細工します。具体的には以下のフィルタのようです。

> /usr/lib/cups/filter/texttops
> /usr/lib/cups/filter/texttopaps

二つありますが違いはよくわかりません。。

(たぶん/usr/share/cups/mimeあたりのファイルから推測するに前者は使われてないようです)


4.フィルタの差し替え
先ほど述べた二つのフィルタを差し替えてしまいましょう。以下のプログラムを

> /usr/lib/cups/filter/texttops-my

という名前で保存して(chmod +x)して下さい。

```
#!/usr/bin/perl

$ENV{"LANG"} = "ja_JP.UTF-8";
$ENV{"LC_ALL"} = "ja_JP.UTF-8";
undef $ENV{"DISPLAY"};

$logfile ="/dev/null";
#$logfile="/tmp/texttops-my-log.txt";
$a2ps="/usr/bin/paps";

$nkf="/usr/bin/nkf";

open(LOG, ">> ${logfile}") || die "Open Error";

$jobtitle = $ARGV[2];
$user = $ARGV[1];
$inputfile = $ARGV[5];

#chmp $inputfile;

print LOG join (":", @ARGV), "\n";

unless(open(INPUT, "< ${inputfile}"))
{
    print LOG "Input Error a2ps\n";
    close(LOG);
    die "Input Error a2ps";
}

print LOG "Input file ${inputfile}\n";

umask(077);
$outfile = "/var/tmp/texttops-my.$$";

print LOG "CUPS_SERVER $ENV{\"CUPS_SERVER\"}\n";

# papsは以下の条件でフィルタモードになるので、抑制
#       if (strncmp(prgname, "texttopaps", 10) == 0 ||
#           getenv("CUPS_SERVER") != NULL) {
#
#
delete($ENV{"CUPS_SERVER"});

#foreach(sort keys %ENV){
#    printf LOG "%s = %s\n",$ENV{$_},$_;
#}

print LOG "CUPS_SERVER = \"$ENV{\"CUPS_SERVER\"}\"\n";
unless(open(OUT, "| ${nkf} -w | ${a2ps} --font=\"Sazanami Gothic\" --font=10 --paper=a4 >& ${outfile}"))
{
    print LOG "Output Error a2ps\n";
    close(LOG);
    die "Output Error a2ps";
}
print LOG "Step 2\n";

while(<INPUT>)
{
    print OUT $_;
    #print LOG $_;
}

close(INPUT);
close(OUT);
#unlink $outfile;

print LOG "Step 3\n";

open (FP, "< ${outfile}") || die;

while(<FP>)
{
    print $_;
}
close(FP);

unlink $outfile;

print LOG "Step 4\n";
exit;
```

そしてファイルを差し替えてしまいましょう。

```
yum install nkf (nkfが無ければ入れてください)

chmod +x /usr/lib/cups/filter/texttops-my

(ファイル差し替え)
cd /usr/lib/cups/filter
mv texttopaps texttopaps.ORG
ln -s texttops-my texttopaps
mv texttops texttops.ORG
ln -s texttops-my  texttops

(再起動)
/etc/rc.d/init.d/cups restart
```

以上で作業は終わりです。lprコマンドで印刷して

> lpr `日本語のプレインテキスト.txt`

日本語が以前よりマトモに出るようになりましたか？？　

フォントとか気に入らなければプログラムを書き換えて下さい。

5.プログラム(texttops-my)補足
短いプログラムですのでソースをごらんいただければと思いますが１点だけ補足しておきます。

このプログラムは、実態としては、プレインテキストをポストスクリプトに変換するときに使うフィルタ/usr/bin/papsに日本語フォントの指定とフォントサイズを指定しているだけですね。

この/usr/bin/papsなのですが、コマンドラインから実行したときとcupsから呼び出された時では挙動が違います。cupsから呼び出された時はコマンドライン引数の体系がマニュアル(man paps)と異なってしまうため、コマンドラインと同じ引数を受け付けるように

> delete($ENV{"CUPS_SERVER"});

と記載しています。具体的にはpapsのソースコードを参照下さい。

(この違いの原因究明には１日を要した。。)

次に、なんらかの障害でtexttops-myが異常終了した場合 /var/tmp に作業ファイルが残る可能性があります。定期的に消して下さい。。もしくは作業ファイルを作らないように書き換えて下さい。

追記：（２０１５・８・３０）
CentOS6.6から6.7に更新したところ
/usr/lib/cups/filter/texttops
がOSの元のファイルに戻りました。差し戻してください。

以上