美文网首页扫码区域设置
二维码扫描 AVCaptureMetadataOutput se

二维码扫描 AVCaptureMetadataOutput se

作者: fallrainy | 来源:发表于2017-02-27 16:19 被阅读689次

    核心代码

        self.output = [[AVCaptureMetadataOutput alloc] init];
        [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
        [self.output setRectOfInterest:({
            //竖屏时 二维码扫描框frame
            CGRect portraitScanningRect = QRCodeScanningRect;
            //横屏时 AVCaptureVideoPreviewLayer size
            CGSize landscapePreviewSize = CGSizeMake(CGRectGetHeight(videoPreviewFrame), CGRectGetWidth(videoPreviewFrame));
            //横屏时 二维码扫描狂frame
            CGRect landscapeScanningRect = ({
                CGRect rect;
                rect.origin = CGPointMake(portraitScanningRect.origin.y, landscapePreviewSize.height - CGRectGetMaxX(portraitScanningRect));
                rect.size = CGSizeMake(CGRectGetHeight(portraitScanningRect), CGRectGetWidth(portraitScanningRect));
                rect;
            });
            //预设视频输入高宽比
            CGFloat p1 = 1080./1920.;
            //AVCaptureVideoPreviewLayer 高宽比
            CGFloat p2 = landscapePreviewSize.height / landscapePreviewSize.width;
            /**
              屏幕高宽比 和 视频预设不相符时,需要做适当修正
             */
            CGRect rectOfInterest = ({
                CGRect rect;
                if (p1 < p2) {//屏幕宽度小于预设宽度,需对x进行修正
                    CGFloat fitWidth = landscapePreviewSize.height / p1;//(当前实际高度对应的预设宽度)
                    CGFloat xOffset = (fitWidth - landscapePreviewSize.width) / 2;
                    rect.origin.x = (landscapeScanningRect.origin.x + xOffset)/landscapePreviewSize.width;
                    rect.origin.y = landscapeScanningRect.origin.y / landscapePreviewSize.height;
                } else {//屏幕高度小于预设高度,需对y进行修正
                    CGFloat fitHeight = landscapePreviewSize.width * p1;//(当前实际宽度对应的预设高度)
                    CGFloat yOffset = (fitHeight - landscapePreviewSize.height) / 2;
                    rect.origin.x = landscapeScanningRect.origin.x / landscapePreviewSize.width;
                    rect.origin.y = (landscapeScanningRect.origin.y + yOffset)/landscapePreviewSize.height;
                }
                rect.size.width = CGRectGetWidth(landscapeScanningRect) / landscapePreviewSize.width;
                rect.size.height = CGRectGetHeight(landscapeScanningRect) / landscapePreviewSize.height;
                rect;
            });
            rectOfInterest;
        })];
    

    注意以下几点:

    1.setRectOfInterest 是相对于横屏而言的,此时坐标原点为竖屏时的右上角
    2.setRectOfInterest 是扫描识别区域frame和AVCaptureVideoPreviewLayer 宽高的比值,而不是扫描识别区域frame本身

    补充

    后续发现,其实 AVCaptureVideoPreviewLayer类已经提供了便捷的计算RectOfInterest的方法

    //未保证正确计算rectOfInterest 需要监听 AVCaptureInputPortFormatDescriptionDidChangeNotification通知
        __weak typeof(self) weakSelf = self;
        [[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureInputPortFormatDescriptionDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) {
            __strong typeof(weakSelf) strongSelf = weakSelf;
            strongSelf.output.rectOfInterest = [strongSelf.previewLayer metadataOutputRectOfInterestForRect:QRCodeScanningRect];
        }];
    
    附加:

    二维码扫描Demo https://github.com/Nomeqc/QRCodeScanningDemo

    相关文章

      网友评论

        本文标题:二维码扫描 AVCaptureMetadataOutput se

        本文链接:https://www.haomeiwen.com/subject/qnfnwttx.html