この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
大阪オフィスの山田です。SwiftでQRコードを表示してみました。それと、おまけとしてQRコードを目で読む方法について調べてみたので書き留めておきます。
開発環境
- Xcode 11.1
- macOS 10.14.6
SwiftでQRコードを表示する
以下のような画面を用意しました。上のtextFieldにQRコードにする値を、下のtextFieldには誤り訂正レベルを入力します。 textが更新されるたびに、QRコードを生成して画面に表示します。
ソースコードはこちら。
class QRCodeViewController: UIViewController {
@IBOutlet weak var messageTextField: UITextField!
@IBOutlet weak var correctionLevelTextField: UITextField!
@IBOutlet weak var qrImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
messageTextField.addTarget(self, action: #selector(self.textFieldDidChange), for: UIControl.Event.editingChanged)
correctionLevelTextField.addTarget(self, action: #selector(self.textFieldDidChange), for: UIControl.Event.editingChanged)
}
enum InputCorrectionLevel: String {
case L
case M
case Q
case H
}
private var QRImage: UIImage? {
guard let message = messageTextField.text,
let correctionLevelString = correctionLevelTextField.text,
let correctionLevel = InputCorrectionLevel(rawValue: correctionLevelString) else { return nil }
let data = message.data(using: .utf8)!
let qr = CIFilter(name: "CIQRCodeGenerator", parameters: ["inputMessage": data, "inputCorrectionLevel": correctionLevel.rawValue])!
let sizeTransform = CGAffineTransform(scaleX: 10, y: 10)
let qrImage = qr.outputImage!.transformed(by: sizeTransform)
let image = UIImage(ciImage: qrImage)
return image
}
@objc func textFieldDidChange() {
qrImageView.image = QRImage
}
}
QRコードの生成について解説
まず、TextFieldに入力された文字列をData?
型に変換します。CIFilter
にCIQRCodeGenerator
を指定して生成します。parameterとしてinputMessage
, inputCorrectionLevel
を与えます。inputMessage
は、QRコードにする値を指定し、inputCorrectionLevel
は誤り訂正レベル
を指定します。誤り訂正レベル
については後ほど解説します。CoreImageFilterのReferenceはこちらです。次にCore Graphicの二次元画像を生成するためのアフィン変換行列CGAffineTransform
を生成し、CIFilterと組み合わせて、QRコード画像のデータ(CIImage)を作成します。CIImageを作成した後、UIImageを作成し、UIImageViewのimageプロパティにセットして、画面に表示します。サンプルコードを見てもらうとわかりますが、生成するQRコードのバージョンを指定することはできないようです。先ほどのCoreImageFilterのRefrerenceを見ても、バージョンを指定するパラメータは無さそうです。
アフィン変換行列について
今回のブログでは詳しく掘り下げません。筆者があまりわかってないためです。深掘りした時はブログを書こうかなと思います。
QRコードについて
QRコードの仕様については、QRコードドットコム:株式会社デンソーウェーブこちらのページがまとまっています。この記事も参考にさせていただいています。
誤り訂正レベルとは
QRコードは汚れていたり破損していたりしていてもある程度自ら復元することが可能です。誤り訂正レベルは4段階存在し、高レベルであれば訂正能力は上がりますが、コードのサイズは大きくなります。同じデータで誤り訂正レベルを変化させた画像を貼っておきます。LよりもHの方がセルのサイズが小さくなってより、多くのセルを含んでいることがわかります。
L | M | Q | H |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
おまけ
QRコードを目で読んでみる
こちらの記事が参考になります。肉眼でも読める!QRコード入門
また、QRコードの英語のWikipediaがとても情報量が多いので、目で読む際は参考にしました。以下のQRコードを読んでみたいと思います。
QRコードの構成
全ては上手に紹介仕切れませんが、目で読むのに必要な部分だけ紹介しておきます。
- タイミングパターン: 白黒パターンが交互に配置されています。データの読み取り歪みを補正します。例えばリーダの仰角、傾角、曲面に貼られていた場合などの歪みを補正します。詳細についてはこちらのPDFの3-3.タイミングパターンを参照してください。
- フォーマット情報: 誤り訂正レベルと後述するデータ領域のマスクパターンの情報を持っています
- ファインダパターン: QRコードの位置を検出するためのパターンで、全方向(360°)から検出可能となっています
- アライメントパターン: タイミングパターン同様、歪みを補正します。詳細についてはこちらのPDFの3-2.アライメントパターンを参照してください。
フォーマット情報を読む
実際に目で読む際は5つのセルだけ読めばOKです。
この場合ですと、黒を1とすると11101
になります。これは10101
でマスクされていますので、解除すると01000
となります。最初の2bitの01
は誤り訂正レベルがL
であることを示しています。後ろ3桁はQRコード全体にかかるマスクの種類を表しています。この場合のマスクは (i+j) % 2 = 0
となるのでゴシック模様のようにマスクがかかっていることとなります。
フォーマット情報についてはこちらの図がとてもわかりやすいです。マスクのパターンも記載されているので、目でQRコードを読む人は一度みてみてください。
マスクを考慮しつつ読んでいく
データの読み方はQRコードの右下から2列ずつジグザグに読んでいきます。右下、左下、右上、左上、さらにその右上、左上といった感じです。一番上まで行くと、左に移動したあと、折り返してジグザグに下に降りてきます。以下の画像のような読み方になります。
エンコードモードとデータの長さ
右下の4つのセルを読みます。先ほど説明した通り、読み方は2列で右下、左下、右上、左上という風にジグザクに読んでいきます。セルの値を読んだら次はマスクがかかっているので、マスク部分を反転します。
1101
<- セルの値1001
<- マスク0100
<- 値: 8bit mode
8ビットバイトモードであることがわかります。他のエンコーディングモードについては省略します。 次の8セルにデータの長さが記載されています。
10000011
<- セルの値10011001
<- マスク00011010
<- 値: 0x1A -> 26文字
データを読む
8bitずつ読んでいき、対応表で文字に置き換えていきます。対応表はこちらを参考にさせていただきました。
. .. ...
途中で力尽きました(´・ω・`)
https://dev.cl
まで解析しました。アライメントパターンや、フォーマット情報の領域は、避けて読んでいきます。
力尽きたところまでの僕のメモです。
- 11110001
- 10011001
- 01101000 -> 68 -> h
- 11101101
- 10011001
- 01110100 -> 74 -> t
- 11100010
- 10010110
- 01110100 -> 74 -> t
- 00010110
- 01100110
- 01110000 -> 70 -> p
- 00010101
- 01100110
- 01110011 -> 73 -> s
- 01011100
- 01100110
- 00111010 -> 3A -> :
- 01000110
- 01101001
- 00101111 -> 2F -> /
- 10111001
- 10010110
- 00101111 -> 2F -> /
- 00000010
- 01100110
- 01100100 -> 64 -> d
- 00111100
- 01011001
- 01100101 -> 65 -> e
- 11101111
- 10011001
- 01110110 -> 76 -> v
- 01001000
- 01100110
- 00101110 -> 2E -> .
- 11111010
- 10011001
- 01100011 -> 63 -> c
- 00111111
- 01010011
- 01101100 -> 6C -> l
おわり
QRコードは別に目で読まんでもええんちゃうかな。