[小ネタ] RustでQRコード生成ツールを実装する
はじめに
モバイルアプリのバックエンドシステムの開発をするときに、実機での挙動を確認するため任意のURLにアクセスしたいことがあります。 今までは下記の方法で対応していました。
- ローカルHTTPサーバをたててHTMLのリンクを踏ませる
- 手入力でがんばる
HTMLのメンテナンスはだんだんと面倒になり、長いURLだと手入力するのが苦痛になってきます。 そこで、QRコードを活用してスキャンするだけでURLにアクセスできるようにしてみましょう。
前提条件
- macOS: 10.12.6
- Rust: 1.25.0 (84203cac6 2018-03-25)
- clap-rs: 2.31.2
- qrcode-rust: 0.5.0
- image: 0.17.0
ツール概要
既製のツールを使っても良いんですが、今回はRustに慣れるため自分で実装してみました。開発環境のセットアップ手順は こちらの記事 を参照してください。
ソースコードは GitHubのリポジトリ で公開しています。
処理概要
下記の流れで処理を実装します。
- 引数解析
- QRコード生成
- 結果出力
引数解析
-o
オプションで出力ファイルを指定して、引数の文字列をQRコードに埋め込む仕様とします。
解析した結果を設定する構造体を定義します。
struct GenerateOptions { text: String, output: Option<PathBuf>, }
次にコマンドライン引数を解析します。
// 引数の解析ルールを定義して評価する let matches = App::new("qr-text") .version("0.0.1") .author("yoshihitoh") .about("指定した文字列のQRコードを生成します。") .arg( Arg::with_name("OUTPUT") .short("o") .long("output") .value_name("FILE") .takes_value(true) .help("出力先のファイルパスを指定してください。"), ) .arg( Arg::with_name("TEXT") .required(true) .help("QRコードに埋め込む文字列を指定してください。"), ) .get_matches(); // 引数の値とオプションを取り出す。 // TEXT: required指定なのでunwrapで取り出す。 (引数エラーの場合はここに到達しない) let text = String::from(matches.value_of("TEXT").unwrap()); // OUTPUT: 任意指定なので、指定されている場合のみ [PathBuf]() に変換する let output = matches.value_of("OUTPUT").map(PathBuf::from); // 構造体に値を設定する let generate_options = GenerateOptions { text, output };
clap-rs
を使うとコマンドライン引数を簡単に解析できます。 --help
コマンドも追加してくれるので確認してみましょう。
$ ./target/release/qr-text --help qr-text 0.0.1 yoshihitoh 指定した文字列のQRコードを生成します。 USAGE: qr-text [OPTIONS] <TEXT> FLAGS: -h, --help Prints help information -V, --version Prints version information OPTIONS: -o, --output <FILE> 出力先のファイルパスを指定してください。 ARGS: <TEXT> QRコードに埋め込む文字列を指定してください。
それっぽい感じのヘルプテキストになっていますね。
QRコード生成
次に、QRコードを生成しましょう。引数解析結果の generate_options.text
をQRコードに変換します。
// QRコード生成 let code = QrCode::new(generate_options.text.as_bytes())?;
QrCode::new で生成する場合、誤り訂正機能はレベルMになります。それ以外のレベルを指定する場合、バージョンを指定する場合は QrCode::with_error_correction_level や QrCode::with_version を使用しましょう。
結果出力
最後に、QRコードをレンダリングしましょう。 GitHubのリポジトリ を確認したところ、下記のフォーマットに対応しているようです。
- ラスタ画像 (png)
- ベクタ画像 (svg)
- 文字列
今回は白黒のラスタ画像をレンダリングします。
// 画像に変換する let image = code.render::<Luma<u8>>().build();
動作確認
動作確認のため、本ブログ記事URLのQRコードを生成してみます。
# リリース版をビルド cargo build --release # QRコード生成 ./target/release/qr-text -o qr-code.png 'https://dev.classmethod.jp/tool/generate-qr-code-in-rust/'
生成したQRコードです。
実機のQRコードスキャナで本記事へのリンクを開けるようになりました!
おわりに
QRコードを活用してURL入力の手間を省くことができました。今後もこういった簡単なツールの実装でRustに慣れて、業務に適用できるようにしていきたいです!