2014年11月9日日曜日

Roltoへの印刷機能をswiftで書く(本編2)

前回に引き続き、小型プリンターRoltoを使うRoltoControllerクラスをswiftで書きます。前回は、Roltoを検索する機能だけで終わったので、今回は残りの機能を一気に紹介しましょう。前回は(RoltoのSDKが提供している)RoltoPrintDiscoverクラスが中心でしたが、今回はRoltoPrintクラスが中心となります。

 

今回最初に作るのは、プリンターの状態を調べるメソッドです。

// プリンタの状態を調べる
func getPrinterStatusF() {
    strProcStatus = PRINTER_PROC_GO      // 処理開始に設定
    if (roltoP == nil) { // ロルトが登録されてなければ中止
        strMsgResult = "Roltoが接続されていません。"
        strProcStatus = PRINTER_PROC_NG  // 処理失敗に設定
        return
    }
    if flagPrinting {  // 印刷中なら中止
        strMsgResult = "印刷中のため使えません。"
        strProcStatus = PRINTER_PROC_NG // 処理失敗に設定
        return
    }
    roltoP.requestPrinterStatus( { (rResult, rStatus) in
        self.setMsgStatusF(rResult, rStatus)
    } )
}
// ロルト状況のメッセージをセット
func setMsgStatusF(rResult:Bool, _ rStatus:RoltoPrinterStatus) {
    if !rResult {
        strMsgResult = "Roltoの状態取得に失敗しました。"
        strProcStatus = PRINTER_PROC_NG  // 処理失敗に設定
        return
    }
    strProcStatus = PRINTER_PROC_NG      // 処理失敗に仮設定
    switch (rStatus) {
    case 0:          // RoltoPrinterStatusIdle
        strMsgResult = "アイドル状態で印刷待ちです。"
        strProcStatus = PRINTER_PROC_OK  // 処理成功に設定
    case 1:          // RoltoPrinterStatusPrinting
        strMsgResult = "印刷中です。"
    case 2:          // RoltoPrinterStatusWritingFirmware:
        strMsgResult = "ファームウェア更新中です。"
    case 3:          // RoltoPrinterStatusCoveropen
        strMsgResult = "カバーが開いています。"
    case 4:          // RoltoPrinterStatusPaperOut
        strMsgResult = "用紙がありません。"
    case 5:          //RoltoPrinterStatusOverheated
        strMsgResult = "オーバーヒート中です。"
    default:
        strMsgResult = "想定外の状態です。"
    }
}

登録が成功してなくても呼ばれる可能性があるため、RoltoPrintが登録されているか調べ、登録されてない場合はエラーメッセージをセットします。印刷中というのは、印刷メソッドのところで出てきますので、ここでは説明を省きます。

前回と同じように、問い合わせ終了後の実行ブロックは関数として外に出し、スッキリさせています。返ってきた結果から、それぞれに対応するメッセージをセットするだけです。Roltoの状態を得るのに成功しても、印刷できる状態でない場合は、すべて処理失敗として扱っています。つまり、Roltoで印刷できる場合にだけ「OK」を返すということです。

 

もう1つ、プリンターが接続中かどうか、調べるメソッドも用意します。

// 
func checkPrinterOnF() -> Bool {
    if (roltoP == nil) { return false }
    return true
}

印刷などでプリンターを利用する前に、チェックするためです。

 

続いて、呼び出す側のswiftコードです。

// プリンターの状態を調べる関数
func getRoltSatus() {
    if flagUsePrinter { return }    // 何かの処理中なら中止
    if !(printerCtrl.checkPrinterOnF()) {  // プリンターが登録されていない場合は、
        findPrinterF()                     // プリンターを検索する(前回に作成)
        return
    }
    // プリンターの状態を問い合わせる
    flagUsePrinter = true
    setMsgPrintF("プリンターの状態を問い合わせ中。")
    printerCtrl.getPrinterStatusF()
    // 指定した回数だけ、結果を問い合わせる
    intRecallCount = 6
    runIntervalF(1.0, self, "getProcResultF") // 前回作った繰り返し関数を利用
}

一番最初は、何かを実行していないか、プリンターが登録されているかをチェックし、条件を満たさなければ中止します。開始後には、実行の終了を待つために、前回用意したgetProcResultF関数を使っています。指定した秒数だけ、終わるまで問い合わせ続けます。

 

また、RoltoControllerクラスの話に戻りましょう。次に作るのは、印刷するメソッドですが、その前に画質パラメーターを設定する変数とメソッドを用意します。

// 画質に関係するパラメータ3つ
var paramErrorDiff : Bool = true
var parmBlockSize : NSNumber = 0.5
var parmBinOffset : NSNumber = 0.5

func setImageParams(rP1:Bool, _ rP2:NSNumber, _ rP3:NSNumber) {
    paramErrorDiff = rP1
    parmBlockSize = rP2
    parmBinOffset = rP3
}

見てのとおり、値のチェックを省略してます。気になる方は、チェックを入れたほうがいいでしょうね。

 

いよいよ、印刷するメソッドです。UIImage画像を受け取って、Roltoを呼び出します。

// 印刷中を表す変数
var flagPrinting : Bool = false  // 印刷中はture
// 画像を印刷するメソッド
func printImageF(rImage:UIImage) {
    strProcStatus = PRINTER_PROC_GO        // 処理開始に設定
    if (roltoP == nil) {  // ロルトが登録されてなければ中止
        strMsgResult = "Roltoが接続されていません。"
        strProcStatus = PRINTER_PROC_NG    // 処理失敗に設定
        return
    }
    if flagPrinting {  // 印刷中なら中止
        strMsgResult = "印刷中のため使えません。"
        strProcStatus = PRINTER_PROC_NG // 処理失敗に設定
        return
    }
    let iParams:Dictionary = [RoltoPrintParameterBlockSize:parmBlockSize, 
        RoltoPrintParameterBinarizationOffset:parmBinOffset, 
        RoltoPrintParameterErrorDiffusion:paramErrorDiff]
    flagPrinting = true    // 印刷中に設定
    roltoP.performPrintImage(rImage, params: iParams, completion: {(rResult) in
        self.setMsgResultF(rResult)
        self.flagPrinting = false    // 印刷中を解除
    })
}
// 印刷結果のメッセージをセットする関数
func setMsgResultF(rResult:RoltoPrintResult) {
    strProcStatus = PRINTER_PROC_NG    // 処理失敗に仮設定
    switch (rResult) {
    case 0:          // RoltoPrintResultSuccess:
        strMsgResult = "正常に印刷されました。"
        strProcStatus = PRINTER_PROC_OK // 処理成功に設定
    case 1:          // RoltoPrintResultUserCancel:
        strMsgResult = "印刷がキャンセルされました。"
    case 2:          // RoltoPrintResultCommunicationError:
        strMsgResult = "通信エラーが発生しました。"
    case 3:           //RoltoPrintResultPaperOutError:
        strMsgResult = "用紙がありません。"
    case 4:           //RoltoPrintResultOverheatError:
        strMsgResult = "オーバーヒートで使えません。"
    case 5:          // RoltoPrintResultCoverOpenError:
        strMsgResult = "カバーが開いてて使えません。"
    case 6:           //RoltoPrintResultPrinterBusyError:
        strMsgResult = "印刷中のため使えません。"
    case 7:           //RoltoPrintResultUnexpectedError:
        strMsgResult = "原因不明のエラーが発生しました。"
    default:
        strMsgResult = "想定外のエラーが発生しました。"
    }
}

他と同じように、印刷終了後の処理ブロックは外に出しました。印刷開始や終了を知らせるための値をセットするのは他と同様です。

印刷開始から終了までの間だけ、印刷中を示すフラグをtrueにしています。検索や印刷をそのまま実行しても、印刷中のメッセージ番号が返るので分かります。しかし、自分からの印刷依頼だけは自分で分かるので、プリンターへの余計なアクセスを減らすために、付けたほうが良いと判断しました。メーカーのサンプルがそうなっていたので、そのまま真似したものです。

 

これを呼び出す側のswiftコードです。

// 画像を受け取ってプリンターへ印刷する関数
func printImageRoltoF(rImage:UIImage) {
    if flagUsePrinter { return }    // 何かの処理中なら中止
    if !(printerCtrl.checkPrinterOnF()) {
        setMsgPrintF("プリンターが接続されていません。")
        runIntervalF(4.0, self, "clearMsgPrintF")
        return
    }
    // メッセージを表示して、繰り返しの準備
    flagUsePrinter = true
    setMsgPrintF("プリンターに印刷を依頼中。")
    // プリンターで印刷
    printerCtrl.printImageF(rImage)
    // 指定回数だけ繰り返しながら、印刷の状態を問い合わせる
    intRecallCount = 50
    runIntervalF(1.0, self, "getProcResultF") // 前回作った繰り返し関数を利用
}

最初には、プリンター関係の何かを実行中と、プリンターが接続中かを調べ、大丈夫なら印刷を開始します。他のメソッドと同じように、指定された秒数だけ繰り返して問い合わせ、印刷結果をメッセージ欄に表示します。

 

再び、RoltoControllerクラスの話に戻りましょう。残りのメソッドも作りました。印刷の途中キャンセルと、プリンターの登録解除です。

// 印刷のキャンセル
func cancelPrintF() {
    roltoP.cancelPrint()
}

// プリンターの登録を解除
func releasePrinterF() {
    roltoP = nil
}

2番目の登録解除ですが、RoltoのSDKにはプリンターを解除する機能がないため、メモリーを解放するぐらいの効果しかありませんね。

 

以上、RoltoControllerクラスの中身と、その利用例のswiftコードを紹介しました。利用する側の例では独自ライブラリの関数を多用してます。でも、RoltoControllerクラスのほうでは使ってないので、汎用的に使えるクラスだと思います。

タイマーを使って問い合わせる処理も、RoltoControllerクラスに入れようかと考えました。しかし、利用する側の処理なので控えました。このままの形のほうが機能を明確に分けられているし、それでも再利用性が高いと思ったからです。

どのアプリでも、今回のRoltoControllerクラスを追加することで、Roltoから印刷する機能が簡単に追加できるでしょう。また、別なプリンターをサポートするコードも、ここで紹介した考え方で作れば、同様に再利用しやすいクラスとして仕上げられます。さらには、プリンターが違っても、メソッドを可能な限り同じに作れば、アプリでのプリンター切り替えが簡単になります。

今回の考え方を参考にして、機能などをどこで区切ったらよいのか考えながら、印刷機能や他の機能を作ってみてください。

0 件のコメント:

コメントを投稿