AirPrint Bridge で古いプリンタを iPhone から印刷できるようにした(日本語環境とドライバでハマった件)

自宅の Mac mini で、以前は Printopia を使って非 AirPrint のプリンタを iPhone / iPad から印刷できるようにしていました。

ところが macOS のバージョンアップや Printopia の有料化もあって、いつの間にかプリンタ共有自体を使わなくなっていました。

我が家では年に数回しか印刷しないので、そのまま放置していたのですが…久しぶりに印刷する用事ができました。

せっかくなので無料で AirPrint できる方法はないかと調べたところ、GitHub に AirPrint Bridge というスクリプトが見つかったので導入してみました。

結果的に印刷できるようになりましたが、途中で2つの別々の問題にハマったので記録しておきます。

AirPrint Bridge とは

macOS で共有しているプリンタを、AirPrint 非対応でも iPhone / iPad から見えるようにしてくれるシェルスクリプトです。

macOS に標準で入っているものしか使わず、launchd のサービスとして常駐してくれるとのこと。

ちなみに Printopia は現在 $19.99 で、無料体験は7日間だけのようです。

年に数回のためにはちょっと悩む金額でした。

環境

  • Mac mini(Intel、Core i3-8100B)
  • macOS のシステム言語: 日本語
  • プリンタ: OKI C301(LAN 接続、ポート 9100)
  • AirPrint Bridge v1.3.4(Homebrew で導入)

Homebrew での導入

README の通り brew install airprint-bridge を実行したところ、いきなり失敗しました。

  • brew install airprint-bridge → tap の clone で could not read Username for 'https://github.com' になり失敗
  • brew tap sapireli/AirPrint_Bridge → 同じエラー
  • tap のリポジトリ URL を明示して brew tap → 今度は「trust してください」と言われる
  • brew trust --formula で信頼してから brew install → ようやく成功

※ tap 名から推測されるリポジトリ(homebrew-AirPrint_Bridge)が存在しないため、URL を明示する必要があったようです。

brew tap sapireli/AirPrint_Bridge https://github.com/sapireli/AirPrint_Bridge.git
brew trust --formula sapireli/airprint_bridge/airprint-bridge
brew install airprint-bridge

インストール後は、システム設定の「一般 > 共有 > プリンタ共有」で共有をオンにしてから、sudo airprint-bridge -t でテスト、sudo airprint-bridge -i でサービス登録、という流れです。

症状1: プリンタ共有はオンなのに「共有プリンタなし」

「プリンタ共有」もプリンタ個別のチェックもオンにしているのに、テストもインストールも止まってしまいました。

> sudo airprint-bridge -t
Listing local shared printers...
No shared printers found.
Test aborted: No suitable printers found.

設定画面を何度見直してもオンになっています。

当たり前だけど、まずは設定ミスを疑うやつ。

調べたこと

  • cupsctl で _share_printers=1 になっていることを確認
  • ipptool で直接問い合わせると printer-is-shared = true が返ってくる
  • つまり CUPS 自体は共有状態を正しく認識している

ということで、スクリプト側を読んでみました。

共有プリンタの検出は lpstat -p | awk '{print $2}' でプリンタ名を取り出していました。

スクリプトの冒頭で LANG=C と LC_ALL=C を指定しているのですが、macOS の lpstat はこれを無視して、システムの言語設定(日本語)でメッセージを出すようです。

実際の出力はこんな感じでした。

プリンタOKI_C301_36F3DCは待機中です。Fri Dec 29 ...

「プリンタ」とプリンタ名の間にスペースがないので、awk '{print $2}' では日付の一部(Dec など)が取れてしまいます。

その結果 lpoptions -p Dec が失敗して、「共有プリンタなし」と判定されていました。

日本語環境ならではの落とし穴です…。

対応1: lpstat -e に置き換え

lpstat -e ならプリンタ名だけを1行ずつ出してくれるので、ロケールに左右されません。

インストール済みのスクリプト(/usr/local/opt/airprint-bridge/bin/airprint-bridge)の2か所を直接書き換えました。

# 修正前
allp=$(lpstat -p | awk '{print $2}')
all_printers=$(lpstat -p | awk '{print $2}')

# 修正後
allp=$(lpstat -e)
all_printers=$(lpstat -e)

これで sudo airprint-bridge -i が通り、iPhone や別の PC からプリンタが見えるようになりました。

sudo airprint-bridge -i の実行ログ
> sudo airprint-bridge -i
Checking CUPS permissions...
CUPS remote access is already allowed.
Printer 'OKI_C301_36F3DC' is shared but does not allow all users. Autofixing
Printer 'OKI_C301_36F3DC' now allows all users.
Checking macOS firewall...
Firewall is disabled; skipping.
Listing local shared printers...
Found 1 printer(s) to process:
 - OKI_C301_36F3DC
Generating airprint_bridge_launcher.sh...
Resolving "OKI_C301_36F3DC"...
TXT records:
  rp=printers/OKI_C301_36F3DC
  ty=OKI C301
  note= via mini32
  pdl=application/pdf,image/jpeg,image/urf
  URF=V1.4,DM1,DM2,DM3
  Color=F
  Duplex=T
Generating /Library/LaunchDaemons/com.sapireli.airprint_bridge.plist...
Plist loaded: /Library/LaunchDaemons/com.sapireli.airprint_bridge.plist
Installation complete.

症状2: 見えるようになったのに印刷されない

これで解決…と思ったら、iPhone から印刷してもジョブがキューに溜まったまま進みません。

/var/log/cups/error_log を見ると、こんなエラーが出ていました。

cgpdftoraster: rasterWriteHeader: Unable to write raster stream header: Broken pipe
execv failed: Bad CPU type in executable
PID 89088 (/Library/Printers/OKIDATA/Filters/OKIHC004.plugin/Contents/MacOS/OKIHC004) stopped with status 186 (Bad CPU type in executable)

lipo -info でこのフィルタを調べると、中身は i386 と ppc だけ(2017年製)でした。

macOS Catalina 以降は 32bit のアプリが動かないので、フィルタが起動できていなかったわけです。

つまり AirPrint Bridge とは関係なく、Mac から直接印刷しても失敗する状態でした。

しばらく印刷していなかったので、macOS のバージョンアップでドライバが動かなくなっていたことに全く気づいていませんでした。

対応2: OKI のドライバを更新

  1. OKI の公式サイトから、macOS 対応の最新 Hiper-C ドライバをダウンロードしてインストール
  2. lipo -info で OKIHC004.plugin が x86_64 になったことを確認
  3. 念のため CUPS のプリンタキューを削除して作り直し(デバイス URI と共有設定は元のまま)
  4. Mac からのテスト印刷と、iPhone からの AirPrint 印刷がどちらも紙で出てくることを確認
キューを作り直したコマンド
sudo lpadmin -x OKI_C301_36F3DC
sudo lpadmin -p OKI_C301_36F3DC -E \
  -v "dnssd://OKI-C301-36F3DC._pdl-datastream._tcp.local./?bidi" \
  -P "/Library/Printers/PPDs/Contents/Resources/OKI C301" \
  -o printer-is-shared=true -D "OKI-C301-36F3DC"

補足

  • ドライバ更新の直後、CUPS 上は「完了」なのに紙が出ないことが一度ありました。原因を探ろうと sudo cupsctl LogLevel=debug でログを詳しくしてからもう一度印刷したら、普通に出てきました。結局何だったのかは分かりません。
  • 症状1の修正はインストール済みファイルの直接編集なので、brew upgrade airprint-bridge をすると元に戻ります。アップデート後にまた「共有プリンタなし」になったら、同じ修正をやり直す必要があります。
  • 日本語など英語以外の環境全般で起きそうなので、そのうち GitHub に Issue を出しておこうと思います。

まとめ

無料の AirPrint Bridge で、Printopia なしでも iPhone / iPad から古いプリンタに印刷できるようになりました。

ハマったのは「日本語環境でプリンタが検出されない」と「32bit のままのドライバで印刷されない」の2つで、それぞれ原因はまったく別でした。

年に数回しか印刷しないと、ドライバが動かなくなっていても気づかないのが怖いところです。

もしかすると私の環境だけかもしれませんが、次に印刷するときや brew upgrade したときに同じことをやりそうなので、メモしておきます。