RICOH IPSiO SP6120 を Linux (gs rpdl) から使う

先日買った RICHO IPSiO SP6120Linux から両面印刷ができるようにしてみようと思います。

(なお、環境は Ubuntu 9.10 karmic です)

リコー 両面印刷ユニット タイプ860 509487
リコー (2005-02-16)
売り上げランキング: 16512

先日書いたとおり、Linux からこの IPSiO SP6120 を使うためには、プリンタの設定で Ricoh RPDL IV Laser Printer のドライバを指定します。

この Ricoh RPDL IV Laser Printer ドライバを使う場合、印刷の流れは下記のようになります。

  1. CUPS フロントエンド(が PS に変換)
  2. PPD に foomatic-RIP が指定されているので、それをフィルタドライバとして使用
  3. foomatic-RIP が PPD から gs のコマンドラインを取得
  4. gs の rpdl ドライバを利用して RPDL 形式に変換
  5. CUPS バックエンドがプリンタに送信

で、gs の rpdl ドライバは日本の方が作成された LIPS & ESC/Page & NPDL & RPDL 対応 Ghostscript デバイスドライバが Ghostscript 本体に contribute としてとりこまれています。なので、両面印刷自体には対応しているはずです。

ですが、現状の Ubuntu などで上記プリンタドライバを指定しても両面印刷が有効になりません。これには下記のような理由が存在しています。

  • RPDL (IV) の汎用 PPD を使っているので両面印刷のオプションがない
  • Ghostscript のオプションに -dDuplex 等つけてもなぜか rpdl ドライバで両面印刷が有効にならない*1
  • Ghostscript に含まれる rpdl ドライバの両面印刷用エスケープシーケンスでは(なぜか)両面印刷にならない

1番めは PPD ファイルを手で修正したらどうとでもなります。

いろいろ調べていて2番めと3番めの事象にぶちあたったので、(後述する理由もあるため)gs rpdl ドライバを修正するという方法ではなく、gs の出力を操作するフィルタを書いて、それを PPD ファイルで指定してうまくいくようにするというアプローチをとりました。

gs にわたされたオプションをうまくフィルタで取得する方法がわからなかったので(foomatic-rip を勉強すればうまくできそうな気もするのですがよくわかりませんでした)、gs に渡されたオプションを出力にそのままながすプレフィルタと本体フィルタの2段構成にしました。

プレフィルタは下記のような単純なシェルスクリプトです。

#!/bin/sh

echo -n "# "
echo $*

exec $*

これを、たとえば /usr/share/rpdl/rpdl_prefilt.sh などの名前で保存しておきます。

次が、実際に両面印刷用のエスケープシーケンスを挿入するフィルタです。

#!/usr/bin/perl

use strict;
use warnings;

my $buffer;

binmode \*STDOUT;

my $command = <>;
if ($command !~ m{\A [#] }xmso) {
    print $command;
}
else {
    my $duplex = 0;
    my $tumble = 0;

    foreach my $arg (split m{\s+}xmso, $command) {
        next if $arg !~ m{\A -[dD] (\w+) (?: = (.*) )? \z}xmso;
        my ($param, $value) = ($1, $2);
        next if $param !~ m{\A (?: Duplex | Tumble ) \z}ixmso;

        $value = 1  if ! defined $value;
        $value = 0  if $value =~ m{\A f (?: alse )? \z}ixmso;
        $value = $value ? 1 : 0;

        if ($param =~ m{\A Duplex \z}ixmso) {
            $duplex = $value;
        }
        elsif ($param =~ m{\A Tumble \z}ixmso) {
            $tumble = $value;
        }
    }

#   print {*STDERR} "duplex: $duplex, tumble: $tumble\n";

    if ($duplex) {
        my $code = "\033\022YA06,2 ";

        if ($tumble) {
            $code .= "\033\022YA03,1 ";
        }
        else {
            $code .= "\033\022YA03,2 ";
        }

        binmode \*STDIN;
        if (! defined read \*STDIN, $buffer, 1024) {
            die $!;
        }

        # prepend duplex command to resolution RPDL command
        $buffer =~ s{ ( \033 \022 YA04, ) }{$code$1}xms;

        print $buffer;
    }
}

binmode \*STDIN;

while (my $len = read \*STDIN, $buffer, 1024) {
    print $buffer;
}

これを、たとえば /usr/share/rpdl/rpdl_dup.pl などの名前で保存しておきます。


さいごに、これらのフィルタを使うように PPD ファイルを変更します。

本当は foomatic-db の形式にしたがって xml ファイルを用意するのが順当なんですが、ファイルをいくつか用意するのがめんどいので、汎用 RPDL IV 用に生成された PPD を変更する手をとります。

まずプリンタの設定で Ricoh RPDL IV ドライバを指定したプリンタを作ります。すると該当する PPD が /etc/cups/ppd/ ディレクトリ以下に生成されるので、これをどこかにコピーして下記のようなパッチを当てます(ファイル名は適宜変更してください)。

--- rpdl4.ppd.orig
+++ rpdl4.ppd
@@ -89,9 +89,9 @@
 *ParamCustomPageSize WidthOffset: 4 points 0 0
 *ParamCustomPageSize HeightOffset: 5 points 0 0
 
-*FoomaticIDs: Ricoh-RPDL_IV_Laser_Printer rpdl
-*FoomaticRIPCommandLine: "gs -q -dBATCH -dPARANOIDSAFER -dQUIET -dNOPA&&
-USE -sDEVICE=rpdl%A%Z -sOutputFile=- -"
+*FoomaticRIPCommandLine: "sh /usr/share/rpdl/rpdl_prefilt.sh gs -q -dBATCH &&
+-dPARANOIDSAFER -dQUIET -dNOPAUSE -sDEVICE=rpdl%A%Z -sOutputFile=- - &&
+| perl /usr/share/rpdl/rpdl_dup.pl"
 *End
 
 *OpenGroup: General/General
@@ -221,6 +221,18 @@
 *FoomaticRIPOptionSetting Resolution=600x600dpi: " -r600x600"
 *CloseUI: *Resolution
 
+*OpenUI *Duplex/Double-Sided printing: PickOne
+*FoomaticRIPOption Duplex: enum CmdLine A
+*OrderDependency: 100 AnySetup *Duplex
+*DefaultDuplex: None
+*Duplex DuplexNoTumble/On (Flip on Long Edge): "%% FoomaticRIPOptionSetting: Duplex=DuplexNoTumble"
+*FoomaticRIPOptionSetting Duplex=DuplexNoTumble: " -dDuplex"
+*Duplex DuplexTumble/On (Flip on Short Edge): "%% FoomaticRIPOptionSetting: Duplex=DuplexTumble"
+*FoomaticRIPOptionSetting Duplex=DuplexTumble: " -dDuplex -dTumble"
+*Duplex None/Off: "%% FoomaticRIPOptionSetting: Duplex=None"
+*FoomaticRIPOptionSetting Duplex=None: ""
+*CloseUI: *Duplex
+
 *CloseGroup: General
 
 

で、この PPD を読み込ませるんですが、プリンタの設定からプリンタのプロパティを開き、設定項目の「製造元とモデル」の「変更」ボタンを押します。

ここで、ドライバーを選択という画面が開きますから、「PPD ファイルを提供」を選択して、今しがた作った PPD ファイルを読み込ませます。

これで両面印刷が(おそらく)できると思います。


しかし、残念ながら 2-up などの N-up をするとうまくいきません(コマンドエラーがでる)。これは今回作成したフィルタスクリプトのせいなのか、もともとも Ghostscript rpdl ドライバのせいなのか、わかりませんでした。

未来はあるのか?

んで、gs rpdl ドライバを修正するのに消極的なわけですが。

ひとつは、Ghostscript のドライバは Ghostscript のシステムに組み込まれてしまっている(具体的には libgs にまとめて入ってる)ので、開発がめんどくさいこと。

もうひとつは、

  • 伝統的に Linux で「印刷」というと PS を吐くことだった
  • けど PS を食えないプリンタは?→Ghostscript
    • オープンライセンスの(一時期クローズドライセンスでお金取ってたけど) Postscript インタプリタ
    • 出力デバイスを「ドライバ」という形で作ることができる
    • 昔は Unix/Linux で「プリンタドライバを書く」というと GS のドライバを書くこととイコール
  • しかし今は違う!
    • 今 GS コミュニティに GS ドライバを書いて提供してもリジェクトされる
    • もはや GS ドライバを書くことはできない
    • 代わりの手段:
      • pcl(mono|color)*2
      • Raster*3 なら IJS, CUPS Raster
      • Vector*4 なら OPVP!
Open Source Conference 2009 Tokyo/Spring (Day 1) - なるひこの Linux Printing お勉強日記

のように Ghostscript コミュニティがちと保守的?らしいということ(ただし、rpdl はすでに導入されているドライバなので、バグフィックスという形であれば受け付けてくれる気もする)。

上にあがっているように今は Ghostscript のドライバではなくてもいろいろプリンタドライバを書く選択肢があるので(さらに上記にはあがってないけど、Gutenprint という選択肢もあります)、簡単に仕上げようと思ったら CUPS Raster ドライバを書くのが一番現実的なのではないかと思います(ただし、ドライバ自体の開発に関するドキュメントはあまりない;あとライセンスがよくわかんない。GPL でいいのかな)。

これら現在の Linux の印刷環境まわりについては、CUPS のダイアグラム*2や、OpenPrinting CUPS Quick Start を参照してください。また先ほど引用した Open Source Conference 2009 Tokyo/Spring (Day 1) - なるひこの Linux Printing お勉強日記 も背景がわかりやすいです。

おまけ: Linux から印刷まわりを手動でやってみる

上記のフィルタを作成する上でデバッグ時に利用した方法。

まずは何はなくとも PS 形式のファイルを用意する必要があります。
これは、GNOME の印刷ダイアログで、「ファイルに出力する」を選んで、出力の形式を「Postscript」にすれば簡単に入手可能。

次に、PS 形式のファイルからプリンタ独自の形式に変換する方法。rpdl ドライバを使う場合、

$ gs -q -dSAFER -dNOPAUSE -dBATCH -sDEVICE=rpdl -r600x600 -sPAPERSIZE=a4 \
     -sOutputFile=test.bin test.ps

のようにします。

最後に、このようにして得られた生データをプリンタに出力する方法。

IPSiO SP6120 の場合、9100 番ポート経由(Hewlett Packard 由来のデファクトスタンダードなダイレクト印刷ポート; LPRプロトコルと標準TCP/IPポート・モニタの違い:Tech TIPS - @IT など参照)の印刷が一番簡単だと思います。

あたかもパラレルポートに送るかのようにダイレクトに送れば印刷するので netcat で出力してしまえばいいです。

$ cat test.bin | nc -q 0 PRINTER_ADDRESS 9100

もし数値 IP アドレスなら -n オプションを使ったほうが、名前解決しないので早いです。

*1:浅追いしてみたんですが断念しました。

*2:OPVP は CUPS-external Ghostscript の部分に含まれてしまうので明確に図示されていません