iOS原生QRコード生成&スキャン

8955 ワード

この機能をスキャンすると、私たちはよく知らないわけではありません.微信QQに友达を追加してスキャンし、道端で普及したスキャンをして、食事をしてお金を払ってスキャンします.このスイープアプリの場所は本当に多いようですね.携帯電話を開けてインストールしたアプリを見てみると、ソーシャルアプリがスキャンされ、支払いアプリがスキャンされ、ブラウザもスキャンされています.この掃除は軽視できないようだ.いつあなたのプロジェクトの中であなたのbossはあなたに彼に掃除の機能を追加するかどうか分かりません!iOSの開発でスキャンを行うのは難しくありませんが、QRコード(QRCode)を処理する必要があります.iOS 7の前にサードパーティ製ライブラリZBarとZXingを借りる必要があります.iOS 7以降はAPI持参で簡単にできます.プロジェクトに膨大なサードパーティ製ライブラリを導入したり、コンパイルに問題が発生する心配はありません.
QRコードとは
2次元バーコードとは、1次元バーコードに基づいて別の1次元の可読性を有するバーコードを拡張し、白黒矩形パターンを用いてバイナリデータを表し、デバイスにスキャンされた後、その中に含まれる情報を取得することができる.ウィキペディア
詳細な生成の詳細と原理はQRコードの生成の詳細と原理のこの文章を見ることができます.
スキャンQRコード
まず、具体的な手順を考えてみましょう.大体の流れは、1.デバイスのカメラを開く-->2.QRコード画像のキャプチャを行う-->3.キャプチャされた画像を取得して解析を行う-->4.解析結果を取得して後続の処理を行うことです.これらのプロセスはAVFoundationというライブラリを使用する必要があります.インポートに注意してください.
//    AVCaptureDevice  ,               
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//    AVCaptureDeviceInput  ,    '   '      
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:_device error:nil];
//      ,    AVCaptureMetadataOutput      '  '  ,        
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc]init];
//          ,        
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
//      , AVMetadataObjectTypeQRCode      ,         。             
output.metadataObjectTypes = @[AVMetadataObjectTypeEAN13Code,
                                    AVMetadataObjectTypeEAN8Code,
                                    AVMetadataObjectTypeCode128Code,
                                    AVMetadataObjectTypeQRCode];


キャプチャの設定は完了していますが、「スキャン」を開始していません.スキャンを完了するには、AVCaptureSessionというクラスが必要です.このセッションクラスは、スキャンを1回のセッションと見なし、セッションが開始された後に「スキャン」が開始されます.具体的なコードは次のとおりです.
AVCaptureSession *session = [[AVCaptureSession alloc]init];
[session setSessionPreset:AVCaptureSessionPresetHigh];//     
if ([session canAddInput:input]){
   [session addInput:input];//         
}  
if ([session canAddOutput:output]){
   [session addOutput:output];//         
}


次に、すぐにセッションを開始する(スキャンを開始する)のではなく、セッションのstartRunningメソッドを呼び出すと、画面が黒くなっていることがわかります.カメラのファインダーのサイズが設定されていないためです.ファインダーを設置するにはAVCaptureVideoPreviewLayerというクラスが必要です.具体的なコードは以下の通りです.
AVCaptureVideoPreviewLayer *preview =[AVCaptureVideoPreviewLayer layerWithSession:session];
preview.videoGravity = AVLayerVideoGravityResize;
[preview setFrame:self.view.bounds];//      frame
[self.view.layer insertSublayer:preview atIndex:0];


次にsessionのstartRunningメソッドを呼び出すことができます.このとき、私たちのスキャンは本当に始まります.スキャンの結果を得るには、sessionを実装するエージェントメソッド- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connectionが必要であり、コードは以下の通りである.
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    [self.session stopRunning];//    
    [self.preview removeFromSuperlayer];//     

    if (metadataObjects.count > 0) {
        AVMetadataMachineReadableCodeObject *obj = metadataObjects[0];
        NSString *result = obj.stringValue;//         
        //       ...
    }
}


ユーザーに配慮するには、照明の機能を加えたり、興味エリアを設定したりする必要があります.
  • 興味領域
  • を設ける.
    微信のスキャンを使用すると、スキャンインタフェースの真ん中に矩形の限定ボックスがあり、このボックスが興味領域であることがわかります.この関心領域はAVCaptureMetadataOutputrectOfInterest属性である.rectOfInterestの値の範囲はすべて0-1で、実際のサイズではなく比例して値を取るので、設定するときに注意しなければならない点です.また、rectOfInterestは横スクリーンで計算されるので、縦スクリーンの場合はx軸とy軸を交換します.コードは次のとおりです.
    CGSize size = self.view.bounds.size;
    CGSize transparentAreaSize = CGSizeMake(200,200);
    CGRect cropRect = CGRectMake((size.width - transparentAreaSize.width)/2, (size.height - transparentAreaSize.height)/2, transparentAreaSize.width, transparentAreaSize.height);
    output.rectOfInterest = CGRectMake(cropRect.origin.y/size.width,
                                                  cropRect.origin.x/size.height,
                                                  cropRect.size.height/size.height,
                                                  cropRect.size.width/size.width);
    
    
  • 照明機能
  • を加える.
    照明機能を加えることで、照明条件が悪い場合にスキャン操作を円滑に行うことができます.コードは以下の通りです.
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    NSError *error;
    if (device.hasTorch) {  //           
        BOOL b = [device lockForConfiguration:&error];
        if (!b) {
           if (error) {
              NSLog(@"lock torch configuration error:%@", error.localizedDescription);
           }
           return;
        }
        device.torchMode = (device.torchMode == AVCaptureTorchModeOff ? AVCaptureTorchModeOn : AVCaptureTorchModeOff);
        [device unlockForConfiguration];
        }
    
    

    画像からQRコードを読み込む
    画像からQRコードを直接読み取る機能はiOS 7ではアップルでは実現していないが、iOSではこの機能が埋まっている.主にCoreImageを読み取ります.
    くだらないことは言わないで、直接コードをつけます.
    + (NSString *)scQRReaderForImage:(UIImage *)qrimage{
        CIContext *context = [CIContext contextWithOptions:nil];
        CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];
        CIImage *image = [CIImage imageWithCGImage:qrimage.CGImage];
        NSArray *features = [detector featuresInImage:image];
        CIQRCodeFeature *feature = [features firstObject];
        NSString *result = feature.messageString;
        return result;
    }
    
    

    アルバムから写真を取るという話がある以上、ついでにアルバムから写真を取ることも話しましょう.
    アルバムから写真を取得するには主にUIImagePickerControllerが使われています.これはアップルが私たちに分けてくれたアルバム選択のコントローラです.実現するのも簡単です.
    - (void)readerImage{
        UIImagePickerController *photoPicker = [[UIImagePickerController alloc] init];
        photoPicker.delegate = self;
        photoPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        photoPicker.view.backgroundColor = [UIColor whiteColor];
        [self presentViewController:photoPicker animated:YES completion:NULL];
    }
    
    

    ライブラリから写真を選択した後、UIImagePickerControllerを呼び出すエージェントメソッドを使用して選択した写真を取得します.
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
        [self dismissViewControllerAnimated:YES completion:^{
          //code is here ...  
        }];
    
        UIImage *srcImage = [info objectForKey:UIImagePickerControllerOriginalImage];
        NSString *result = [QRCScanner scQRReaderForImage:srcImage];//                     
        [self.navigationController popViewControllerAnimated:YES];
    }
    
    

    QRコードの生成
    QRコードを生成するには、画像からQRコードを読み出すのと同様にCoreImageを使用します.具体的な手順は、次のとおりです.
    - (UIImage *)makeQRCodeForString(NSString *)string{
        NSString *text = string;
        NSData *stringData = [text dataUsingEncoding: NSUTF8StringEncoding];
        //  
        CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
        [qrFilter setValue:stringData forKey:@"inputMessage"];
        [qrFilter setValue:@"M" forKey:@"inputCorrectionLevel"];
        //     
        UIColor *onColor = [UIColor redColor];
        UIColor *offColor = [UIColor blueColor];
        //  ,         QRCode       
        CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor"
                                              keysAndValues:
                                 @"inputImage",qrFilter.outputImage,
                                 @"inputColor0",[CIColor colorWithCGColor:onColor.CGColor],
                                 @"inputColor1",[CIColor colorWithCGColor:offColor.CGColor],
                                 nil];
        //  
        CIImage *qrImage = colorFilter.outputImage;
        CGSize size = CGSizeMake(300, 300);
        CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:qrImage  fromRect:qrImage.extent];
        UIGraphicsBeginImageContext(size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetInterpolationQuality(context, kCGInterpolationNone);
        CGContextScaleCTM(context, 1.0, -1.0);//   QRCode       ,      
        CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage);
        UIImage *codeImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        CGImageRelease(cgImage);
    
        return [UIImage imageWithCIImage:qrImage];
    }
    
    

    もちろん、このコードを書きたくない場合は、軽量レベルのオープンソースlibqrencodeを使用して実現することもできます.UIImage+MDQRCodeという拡張子を導入すると、UIImageのクラスメソッドを使用して呼び出すことができます.
    + (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)size;
    + (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)size fillColor:(UIColor *)fillColor;
    
    

    QRCScanner
    上のコードさえ少しも書きたくない場合は、一言でスキャン機能を統合したい場合は、QRCScanner、アドレスポイントを使用することができます.