概要
iOSではiOS 13から、CIQRCodeGenerator
というAPIが用意されており、これを用いることでQRコードの画像を簡単に生成することが可能になりました。
公式のドキュメントは以下になります。
この、CIQRCodeGeneratorを使ってのQRコード画像を生成してみたいと思います。
CIQRCodeGeneratorを生成する
CIQRCodeGeneratorはprotocolであり、実際はCIQRCodeGeneratorに適合したCIFilterを作成する形になります。
CIFilterには QRCodeGenerator
というそのものズバリのクラスメソッドが用意されているので、そちらを使ってCIFilterを生成し、message
にQRコード化したいデータ、correctionLevel
にはドキュメントにも記載のある通り、L, M, Q, Hから誤り訂正レベルを文字列で指定することになります。
以下はQITQrCodeGeneratorというクラスに生成処理を設けたコード例です。
#import <Foundation/Foundation.h>
#import <CoreImage/CIFilterBuiltins.h>
NS_ASSUME_NONNULL_BEGIN
@interface QITQrCodeGenerator : NSObject
+ (CIFilter<CIQRCodeGenerator>*)generator:(NSData* )data
correctionLevel:(NSString* )correctionLevel;
@end
NS_ASSUME_NONNULL_END
#import "QITQrCodeGenerator.h"
@implementation QITQrCodeGenerator
+ (CIFilter<CIQRCodeGenerator>*)generator:(NSData* )data
correctionLevel:(NSString* )correctionLevel
{
CIFilter<CIQRCodeGenerator>* filter = [CIFilter QRCodeGenerator];
filter.message = data;
filter.correctionLevel = correctionLevel;
return filter;
}
@end
Swiftから使う
上記のコード例からわかる通り、iOS 13から追加されたCIQRCodeGeneratorは、Objective-Cでしか使えません。
なので上記クラスをブリッジしてSwiftで使うことになります。
サンプルとしてSwiftUIからQRコードを表示するためのコードを例示します。
ポイントとして、CIQRCodeGeneratorから生成されるCIImageは、そのままUIImageにあるinitで変換しようとしてもSwiftUI上で表示されないのと、SwiftUIはマルチプラットフォームなのでSwiftUI.Imageに変換するのが望ましいと考えたので、CIImage→CGImage→Imageの変換を行なっています。
struct ContentView: View {
@StateObject private var model = DataModel()
var body: some View {
VStack {
if let qrImage = model.qrImage {
qrImage
} else {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
}
Text("Hello, world!")
}
.task {
model.showQr(text: "適当な文字列")
}
.padding()
}
}
final class DataModel: ObservableObject {
@Published var qrImage: Image?
func showQr(text: String) {
let urlData: Data = text.data(using: .utf8)!
let qrFilter = OADQrCodeGenerator.generator(urlData, correctionLevel: "H")
// QRコードの拡大処理
let qrOutputImage = qrFilter.outputImage!.transformed(by: .init(scaleX: 5, y: 5))
let context = CIContext()
let qrCgImage: CGImage = context.createCGImage(qrOutputImage, from: qrOutputImage.extent)!
qrImage = .init(qrCgImage, scale: 1.0, label: Text(text))
}
}