の記事にて、BMPからUNIRASTへの変換が完了した。
あとは、BonjourとIPPを実装すれば理論上はXamarin AndroidからAirPrintができるはず。
ということで実装してみた。
Bonjour
Bonjourは、ネットワーク上のデバイスを探すためのプロトコルのよう。
NuGetにPCLでも使えるBonjourライブラリがあったため、今回はこれを使用する。
例えば、ネットワーク上にあるプリンタを列挙したい場合、以下のようなコードを書くことで可能になる。
var printer_search = ZeroconfResolver.ResolveAsync("_printer._tcp.local.");
printer_search.Wait();
var printers = printer_search.Result;
foreach(var printer in printers)
Console.WriteLine(printer);
IPP
AirPrintは実際はIPPを使用して印刷している。
IPPはHTTP上に実装された印刷を制御するためのプロトコル。HTTP上でやりとりが行われているため、プロクシやらSSLやら何やら、HTTPで使用できる技術の恩恵が受けられる点が強みらしい。
遠隔地からの印刷なども、HTTPさえ繋がれば可能になる。
今回は、以下のプロジェクトを参考に、IPPをある程度実装した。
IPPは以下のような書式になっている。(全てビッグエンディアン)
Major Version 1byte
Minor Version 1byte
Operation ID または Status Code 2byte (送信はOperationID、受信はStatusCode)
Request ID 4byte (1以上、リクエスト毎の連番)
-- Group
Group ID 1byte
-- Attribute
Tag ID 1byte
Name Length 2byte
Name (Name Length)byte
Value Length 2byte
Tag ID
-- Attributeの繰り返し
-- Groupの繰り返し
0x03(EndOfAttribute Group ID) 1byte
Groupは、Attributeの集合。操作に関するIDや、ジョブに関するIDなど、Attributeの種類に応じてグループが存在する。
Attributeは、実際の値の集合となっている。この辺からかなり複雑になってくるので、割愛。
実際のやりとりは、プリンタに対して行いたい操作をOperation IDとしてセットし、詳しい設定をAttributeとしてセット、そして送信する。
その後、帰ってきたIPPデータを読み取り、Status CodeがSuccessなどだったら、Attributeを読み込み、結果を取得する。
という流れになる。
今回は、プリンタの情報を取得するGet-Printer-Attributes操作と、ジョブの有効性を判定するValidate-Job操作、実際に印刷をするPrint-Job操作、印刷の状況を取得するGet-Job-Attribute操作を実装した。
## ソースコード
https://github.com/mj-hd/AirPrint.NET
結果
以上、すべてのソースコードがPCL上で完結しているため、Xamarin上で使用することができる。
そして、無事、Xamarin AndroidからAirPrint対応プリンタを通して印刷が行えた。
これにより何が嬉しいかというと、Android標準の印刷ダイアログを表示せずに印刷を行うことができる。
Android標準の印刷機能を使うと、どうしてもユーザに印刷ボタンを押す操作をしてもらう必要が出てしまうため、回避するためにはこう言った工夫が必要なのだと思う。
今後の課題
今現在は多くの印刷に関する設定を、プリンタのデフォルト値にしているため、プリンタによって印刷結果が変わってしまうことがある。
この辺どうにかしたい。けど、テストできるプリンタがない…。
追記:
実は、AirPrintはBonjourを使うとも限らないようで、自分が探した中にも、Bonjour以外の方法でしか探すことのできないプリンタがあった。どういった方法で探索しているかは、ベンダしか知らないようなので、今回の方法ではすべてのプリンタを探索できるわけではないということが分かった。
探索できない場合は、手動でIPアドレスを指定するようにした。