[小ネタ] RustでQRコード生成ツールを実装する

はじめに

モバイルアプリのバックエンドシステムの開発をするときに、実機での挙動を確認するため任意のURLにアクセスしたいことがあります。 今までは下記の方法で対応していました。

  • ローカルHTTPサーバをたててHTMLのリンクを踏ませる
  • 手入力でがんばる

HTMLのメンテナンスはだんだんと面倒になり、長いURLだと手入力するのが苦痛になってきます。 そこで、QRコードを活用してスキャンするだけでURLにアクセスできるようにしてみましょう。

前提条件

ツール概要

既製のツールを使っても良いんですが、今回はRustに慣れるため自分で実装してみました。開発環境のセットアップ手順は こちらの記事 を参照してください。

ソースコードは GitHubのリポジトリ で公開しています。

処理概要

下記の流れで処理を実装します。

  1. 引数解析
  2. QRコード生成
  3. 結果出力

引数解析

-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_levelQrCode::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に慣れて、業務に適用できるようにしていきたいです!