これは便利すぎる! 標準 iOS7 SDK のみで QR コードが読み取れるようになった!!

iOS 開発で QR コードや JAN バーコードを読み取ろうかと思ったら、ZXing, ZXingObjC, ZBar などの利用が考えられますが、ZXing は組み込みが少し面倒で、ZingObjC は導入が簡単でも動作が(ZXing, ZBar に比べて)少し遅く、ZBar は認識が早いがライセンスが LGPL でクライアントへの提案が難しかったりとしっくりくる物がなかったのですが、iOS7 アップデートで標準 SDKQR の読み取り機能が追加されたおかげで一気に問題が解決しそうです。iOS7 SDK 以降というのが少し痛いですが標準 SDK で利用できるというのは大きな利点です。

早速実装コード

以下、実装コードです。iOS7 SDK, Xcode 5 で、 Single View Application を選択して、ViewController を実装します。
ビルド設定でAVFoundation のリンクを忘れずに!

#import <AVFoundation/AVFoundation.h>
#import "QRViewController.h"

@interface QRViewController () <AVCaptureMetadataOutputObjectsDelegate>
@property (strong, nonatomic) AVCaptureSession *session;
@end

@implementation QRViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.session = [[AVCaptureSession alloc] init];

    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    AVCaptureDevice *device = nil;
    AVCaptureDevicePosition camera = AVCaptureDevicePositionBack; // Back or Front
    for (AVCaptureDevice *d in devices) {
        device = d;
        if (d.position == camera) {
            break;
        }
    }

    NSError *error = nil;
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device
                                                                        error:&error];
    [self.session addInput:input];

    AVCaptureMetadataOutput *output = [AVCaptureMetadataOutput new];
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    [self.session addOutput:output];

    // QR コードのみ
    //output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];

    // 全部認識させたい場合
    // (
    // face,
    // "org.gs1.UPC-E",
    // "org.iso.Code39",
    // "org.iso.Code39Mod43",
    // "org.gs1.EAN-13",
    // "org.gs1.EAN-8",
    // "com.intermec.Code93",
    // "org.iso.Code128",
    // "org.iso.PDF417",
    // "org.iso.QRCode",
    // "org.iso.Aztec"
    // )
    output.metadataObjectTypes = output.availableMetadataObjectTypes;

    NSLog(@"%@", output.availableMetadataObjectTypes);
    NSLog(@"%@", output.metadataObjectTypes);

    [self.session startRunning];

    AVCaptureVideoPreviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
    preview.frame = self.view.bounds;
    preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer:preview];
}

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    NSLog(@"----");
    for (AVMetadataObject *metadata in metadataObjects) {
        if ([metadata.type isEqualToString:AVMetadataObjectTypeQRCode]) {
            // 複数の QR があっても1度で読み取れている
            NSString *qrcode = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
            NSLog(@"%@", qrcode);
        }
        else if ([metadata.type isEqualToString:AVMetadataObjectTypeEAN13Code]) {
            NSString *ean13 = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
            NSLog(@"%@", ean13);
        }
    }
}

@end

か、簡単すぎます・・・。

まとめ

というわけで、簡単に QR コードリーダーが実装できてしまいました。
認識も結構早いです。オートフォーカスのないフロントカメラでもさくさく読み取れました。
これは便利すぎる!!

追記:
JAN コードは縦でも横でも読んでくれはするのですが、フロントカメラだと少し厳しいかも・・・。