🎼

【Flutter】QRコードを生成して表示する

に公開

はじめに

「QR コードを生成したい。」

ということで、pretty_qr_codeライブラリを用いて、QR コードを生成してみました。

pretty_qr_codeでは、QR コード生成のデモが用意されているので、まずはそちらでできることの全体像をご確認ください。

pretty_qr_code デモ: Live Preview


【検証時の環境】

flutter doctor
[] Flutter (Channel stable, 3.29.2, on macOS 15.5 24F74 darwin-arm64, locale ja-JP)
[] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
[] Xcode - develop for iOS and macOS (Xcode 16.3)
[] Chrome - develop for the web
[] Android Studio (version 2024.1)
[] VS Code (version 1.101.1)
[] VS Code (version 1.100.0-insider)
[] Connected device (7 available)
[] Network resources


QR コードに関する用語

QR コードについての知識や用語が分からないと適切な設定ができないので、まずは最低限ライブラリで使用する用語について調べてみました。

クワイエットゾーン

QR コード周囲の余白(マージン)のこと。
正確に QR コードを読み取るために必要なスペースです。

誤り訂正レベル

QR コードが一部破損していたり汚れていたとしても、QR コード自身でデータを復元する機能のこと。
この機能のレベルは、L(Low)、M(Medium)、Q(Quartile)、H(High)の 4 段階があります。
レベルが高いほど復元可能能力は向上しますが、データ量も増えます。どのような環境で QR コードを使用するかによって、適切なレベルを選択する必要があります。

※ スマホ表示であれば、破損や汚れ等は基本的に発生しないので、L(Low)で十分かもしれません。デフォルトも L(Low)なことより。

QR コードのバージョン

QR コードのサイズやデータ容量を決定する値。
バージョンは 1 から 40 まであります。
バージョンが大きいほど、より多くのデータを格納できます。

→ QR コードに載せるデータ量(文字数)によって、適切な値を指定する必要があります。

モジュール

QR コードを構成する 1 つの正方形のこと。セルとも呼ばれます。

QR コードバージョン:1 を例に見ると、
21 x 21 のモジュールで構成されている、すなわち、1つの白黒の正方形(1 モジュール)が 21 x 21 で並んでいるイメージです。

コードのバージョンを大きくすると、並ぶモジュール数も多くなり、結果的に多くの情報を埋め込めることになります。


シンプルな QR コードの生成

まずはシンプルな QR コードの生成から見てみます。
一行書くだけで QR コードが Widget として表示されます。

PrettyQrView.data(data: 'https://flutter.dev')

生成された QR コードをスマホから読み込むと、指定した URL が反映されていることが確認できます。
(お手元のスマホで読み取ると認識されることが確認できます。)


QR コードのカスタマイズ

PrettyQrView.dataでは、以下のパラメータを指定できます。

Widget data({
  Key? key,
  required String data,                          // QRコードに埋め込むデータ文字列
  PrettyQrDecoration? decoration,                // QRコードのレイアウト調整
  int errorCorrectLevel = QrErrorCorrectLevel.L, // QRコードの誤り訂正レベル(L, M, Q, H)
  Widget Function(BuildContext, Object, StackTrace?)? errorBuilder, // QRコード生成失敗時に代わりに表示するWidget
})

PrettyQrDecorationについて、以下に設定できることを記載します。

PrettyQrDecoration PrettyQrDecoration({
  PrettyQrDecorationImage? image, // QRコードの中央に配置する画像設定
  PrettyQrQuietZone? quietZone,   // クワイエットゾーンの指定。特段指定がなければ、`PrettyQrQuietZone.standard` の指定で良さそう。直接指定したい場合は.pixels(num)も可。
  Color? background,              // 背景色
  PrettyQrShape shape,            // QRコードの形状設定
})

// ==================
const PrettyQrDecorationImage({
  required super.image,                     // 画像のパス
  super.scale = 0.2,                        // 比率。2.0以下が推奨
  super.onError,                            // 画像読み込み失敗時のコールバック
  super.colorFilter,                        // 画像の色合いの指定
  super.fit,                                // 画像のフィット方法(BoxFit)
  super.repeat = ImageRepeat.noRepeat,      // 画像が小さい場合の繰り返し方法
  super.matchTextDirection = false,         // 画像の水平反転?
  super.opacity = 1.0,                      // 画像の不透明度
  super.filterQuality = FilterQuality.low,  // 画像の拡大縮小する際の品質
  super.invertColors = false,               // 画像の色を反転
  super.isAntiAlias = false,                // 画像のエッジを滑らかにするか
  this.padding = EdgeInsets.zero,           // padding
  this.position = PrettyQrDecorationImagePosition.embedded, // 画像の位置
}) : assert(scale >= 0 && scale <= 1);

// ==================
const PrettyQrSmoothSymbol({
    this.roundFactor = 1,                 // QRコードのドットの角の丸み設定(0.0〜1.0)
    this.color = const Color(0xFF000000), // QRコードの色
})  : assert(roundFactor <= 1, 'roundFactor must be less than 1'),
    assert(roundFactor >= 0, 'roundFactor must be greater than 0');
QR① QR②
コードサンプル
// QR①
PrettyQrView.data(
    data: 'https://flutter.dev',
    decoration: const PrettyQrDecoration(
    image: PrettyQrDecorationImage(
        image: AssetImage('assets/images/flutter_icon.png'),
        scale: 1,
        padding: EdgeInsets.all(40),
        position: PrettyQrDecorationImagePosition.foreground,
    ),
    quietZone: PrettyQrQuietZone.standart,
    shape: PrettyQrSmoothSymbol(
        color: Colors.blue,
        roundFactor: 1,
    ),
    background: Colors.lightGreen,
    ),
    errorCorrectLevel: QrErrorCorrectLevel.H,
),

// QR②
PrettyQrView.data(
    data: 'https://flutter.dev',
    decoration: const PrettyQrDecoration(
    image: PrettyQrDecorationImage(
        image: AssetImage('assets/images/flutter_icon.png'),
        position: PrettyQrDecorationImagePosition.background,
        invertColors: true,
    ),
    quietZone: PrettyQrQuietZone.standart,
    shape: PrettyQrSmoothSymbol(
        color: Colors.deepPurple,
        roundFactor: 0,
    ),
    background: Colors.lightGreen,
    ),
    errorCorrectLevel: QrErrorCorrectLevel.L,
),


文字列以外にバイナリーデータを QR に渡したい場合や、QR コードのバージョンを指定したい場合は、デフォルトの PrettyQrView コンストラクタを用いて指定できます。

final qrCode = QrCode(
    8,
    QrErrorCorrectLevel.H,
)..addData('lorem ipsum dolor sit amet');
// ..addByteData(byteData) // バイナリデータの場合

final qrImage = QrImage(qrCode);

// ....

Widget build(BuildContext context) {
    return PrettyQrView(qrImage: qrImage)

// ===============
class QrCode {
  final int typeNumber;        // QRコードのバージョン(1〜40)
  final int errorCorrectLevel; // QRコードの誤り訂正レベル(L, M, Q, H)
  final int moduleCount;       // QRコードのモジュール数。「typeNumber * 4 + 17」で自動計算されるため、直接指定は不可。
}

Note: Do not create QrImage inside the build method; otherwise, you may have an undesired jank in the UI thread.

※ build の中で QrImage を生成すると不具合が発生するおそれがあるみたいなので、注意が必要です。

コードサンプル
final qrImage = QrImage(
    QrCode(
        12,
        QrErrorCorrectLevel.H,
    )..addData('lorem ipsum dolor sit amet'),
);


Widget build(BuildContext context) {
    return PrettyQrView(
        qrImage: qrImage,
        decoration: const PrettyQrDecoration(
        quietZone: PrettyQrQuietZone.standart,
        shape: PrettyQrSmoothSymbol(
            roundFactor: 0,
        ),
        ),
    ),

備考

画像の配置をPrettyQrDecorationImagePosition.embeddedで配置すると、値が読み込めない現象が発生。
QrErrorCorrectLevelはデフォルトではLowが指定されているため、誤り訂正レベルを上げてQrErrorCorrectLevel.Hを指定することで、読み取り可能な QR コードが生成されるようになりました。

https://github.com/promops/flutter_pretty_qr/issues/43

QrErrorCorrectLevel.L QrErrorCorrectLevel.H

参考リンク

参考リンク
GitHubで編集を提案
NCDCエンジニアブログ

Discussion