iOS二维码扫描

iOS二维码扫描导入AVFoundation库,并将它加入.pch预编译文件给相机预览控制器DTCameraPreviewController添加四个私有成员,获取AVFoundation的“终端”、“输入”、“输出”、“管理员”对象:@implementationDTCameraPreviewController{AVCaptureDevice*_camera;AVCaptureDevice

大家好,又见面了,我是你们的朋友全栈君。

扫码器所用AVFoundation模块图

  1. 导入AVFoundation库,并将它加入.pch预编译文件

  2. 给相机预览控制器DTCameraPreviewController添加四个私有成员,获取AVFoundation的“终端”、“输入”、“输出”、“管理员”对象:


@implementation DTCameraPreviewController

{

    AVCaptureDevice *_camera;

    AVCaptureDeviceInput *_videoInput;

    AVCaptureStillImageOutput *_imageOutput;

    AVCaptureSession *_captureSession;

}
  1. 选取录制设备(摄像头或麦克风)

AVCaptureDevice提供了一个类方法,指定一种媒体类型(AVMediaTypeVideo or AVMediaTypeAudio)它便能返回对应的录制设备。其他媒体类型可以在AVMediaFormat.h中找到,不过它们不需要录制设备(如文本、字幕等)。

DTCameraPreviewController.m中实现_setupCamera方法,用来初始化若干个AVFoundation中用于录制的对象,


- (void)_setupCamera {

    //获取到一个录制设备(摄像头)

    _camera = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];



    //创建摄像头的输入,initWithDevice:方法自动为设备分配了一个端口,每个端口只能传输一路媒体数据

    NSError *error;

    _videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_camera error:&error];

    if (!_videoInput) {

        NSLog(@"Error connecting video input: %@", [error localizedDescription]);

        return;

    }

}
  1. 媒体录制“管理进程”

AVCaptureSession是媒体录制进程的的管理员。控制着设备的输入输出。将输入添加至设备(_setupCamera方法):


    //创建录制“管理进程”,将输入添加至设备

    _captureSession = [[AVCaptureSession alloc] init];

    if (![_captureSession canAddInput:_videoInput]) {

        NSLog(@"Unable to add video input to capture session");

        return;

    }

    [_captureSession addInput:_videoInput];
  1. 显示实时视频预览

苹果提供了预览层AVCaptureVideoPreviewLayer,它可以提供摄像头画面的实时预览。因为它是CALayer的子类,将它封装至UIView,方便使用。所以新建一个继承自UIViewDTVideoPreviewView类。头文件中,定义一个属性以获取视频预览层:


@interface DTVideoPreviewView : UIView

@property (readonly) AVCaptureVideoPreviewLayer *previewLayer;

@end

实现文件:


@implementation DTVideoPreviewView

//代码创建实例时调用

- (id)initWithFrame:(CGRect)frame {

   self = [super initWithFrame:frame];

   if (self)

   {

      [self _commonSetup];

   }

   return self;

}



//通过Nib创建

- (void)awakeFromNib {

    [self _commonSetup];

}



//替代默认的CALayer

+ (Class)layerClass {

    return [AVCaptureVideoPreviewLayer class];

}



- (void)_commonSetup {

    self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

    self.backgroundColor = [UIColor blackColor];

    [self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; 

}

//类型转换

- (AVCaptureVideoPreviewLayer *)previewLayer {

    return (AVCaptureVideoPreviewLayer *)self.layer;

}

@end

将storyboard中的根视图类型改为DTVideoPreviewView

DTCameraPreviewController中添加以下viewDidLoad方法:


- (void)viewDidLoad {

    [super viewDidLoad];

    NSAssert([self.view isKindOfClass:[DTVideoPreviewView class]], @"Wrong root view class %@ in %@", NSStringFromClass([self.view class]), NSStringFromClass([self class]));

    _videoPreview = (DTVideoPreviewView *)self.view; 

    [self _setupCamera];

}

以及在_setupCamera最后将预览图层添加至管理进程中:


_videoPreview.previewLayer.session = _captureSession;

至此,我们已将流程图中的AVCaptureDeviceInput连至预览图层。

启动摄像头需调用-startRunning


- (void)viewWillAppear:(BOOL)animated {

   [super viewWillAppear:animated];

   [_captureSession startRunning];

}



- (void)viewDidDisappear:(BOOL)animated {

    [super viewDidDisappear:animated];

    [_captureSession stopRunning];

}
  1. 设置闪光灯

- (void)_setupTorchToggleButton {

    if ([_camera hasTorch]) {

        self.toggleTorchButton.hidden = NO;

    } else {

        self.toggleTorchButton.hidden = YES;

    }

}

- (IBAction)toggleTorch:(id)sender {

    if ([_camera hasTorch]) {

        BOOL torchActive = [_camera isTorchActive];



        if ([_camera lockForConfiguration:nil]) {

            if (torchActive) {

                if ([_camera isTorchModeSupported:AVCaptureTorchModeOff]) {

                    [_camera setTorchMode:AVCaptureTorchModeOff];

                }

            } else {

                if ([_camera isTorchModeSupported:AVCaptureTorchModeOn]) {

                    [_camera setTorchMode:AVCaptureTorchModeOn];

                }

            }



            [_camera unlockForConfiguration];

        }

    }

}
  1. 抓取照片

完整的_setupCamera


- (void)_setupCamera {

    _camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];



    if (!_camera) {

        [self.snapButton setTitle:@"No Camera Found" forState:UIControlStateNormal];

        self.snapButton.enabled = NO;

        [self _informUserAboutNoCam];

        return;

    }



    NSError *error;

    _videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_camera error:&error];



    if(!_videoInput) {

        NSLog(@"error connectiong video input: %@", [error localizedDescription]);

        return;

    }



    _captureSession = [[AVCaptureSession alloc] init];

    if (![_captureSession canAddInput:_videoInput]) {

        NSLog(@"Unable to add video input to capture session");

        return;

    }

    [_captureSession addInput:_videoInput];



// [self _configureCurrentCamera];

    _imageOutput = [AVCapturePhotoOutput new];



    if (![_captureSession canAddOutput:_imageOutput]) {

        NSLog(@"Unable to add still image output to capture session");

        return;

    }



    [_captureSession addOutput:_imageOutput];



    _videoPreview.previewLayer.session = _captureSession;

}

获取当前链路:


- (AVCaptureConnection *)_captureConnection {

    for (AVCaptureConnection *connection in _imageOutput.connections) {

        for (AVCaptureInputPort *port in [connection inputPorts]) {

            if ([port.mediaType isEqual:AVMediaTypeVideo]) {

                return connection;

            }

        } 

    }

    return nil; 

}

拍照:


- (IBAction)snap:(id)sender {

    if (!_camera) {

        return;

    }



    AVCaptureConnection *videoConnection = [self _captureConnection];



    if (!videoConnection) {

        NSLog(@"Error:No Video connection found on still image output");

    }



    [_imageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {

        if (error) {

            NSLog(@"Error capturing still image: %@", [error localizedDescription]);

            return;

        }

        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation: imageSampleBuffer];

        UIImage *image = [UIImage imageWithData:imageData];

        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);

     }];

}
  1. 对焦

iOS有三种对焦模式:


AVCaptureFocusModeContinuousAutoFocus

AVCaptureFocusModeAutoFocus

AVCaptureFocusModeLocked

监测扫描区域的变化:


- (void)_configureCurrentCamera {

    if ([_camera isFocusModeSupported:AVCaptureFocusModeLocked]) {

        if ([_camera lockForConfiguration:nil]) {

            _camera.subjectAreaChangeMonitoringEnabled = YES;



            [_camera unlockForConfiguration];

        }

    }

}

一旦画面有变化,iOS系统就会发出AVCaptureDeviceSubjectAreaDidChangeNotification通知,我们可以再-viewDidLoad中订阅这一通知:


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    NSAssert([self.view isKindOfClass:[CWVideoPreviewView class]],

             @"Wrong root view class %@ in %@",

             NSStringFromClass([self.view class]),

             NSStringFromClass([self class]));



    _videoPreview = (CWVideoPreviewView *)self.view;

    [self _setupCamera];

    _videoPreview.previewLayer.session = _captureSession;



    [self _setupCameraAfterCheckingAuthorization];



    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];

    [self.view addGestureRecognizer:tap];



    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

    [center addObserver:self

               selector:@selector(subjectChanged:)

                   name:AVCaptureDeviceSubjectAreaDidChangeNotification

                 object:nil];

}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/149600.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • matlab支持向量回归,支持向量回归 MATLAB代码

    matlab支持向量回归,支持向量回归 MATLAB代码支持向量回归MATLAB代码(2013-05-3116:30:35)标签:教育支持向量机和神经网络都可以用来做非线性回归拟合,但它们的原理是不相同的,支持向量机基于结构风险最小化理论,普遍认为其泛化能力要比神经网络的强。大量仿真证实,支持向量机的泛化能力强于神经网络,而且能避免神经网络的固有缺陷——训练结果不稳定。本源码可以用于线性回归、非线性回归、非线性函数拟合、数据建模、预测、分类等多种应…

    2022年6月6日
    95
  • java生成pfx证书[通俗易懂]

    java生成pfx证书[通俗易懂]packagecom.zrsf.cert;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.mat

    2022年6月3日
    235
  • 设计模式–解释器模式(Interpreter)

    设计模式–解释器模式(Interpreter)

    2021年7月30日
    53
  • AjaxPro2完整入门教程[通俗易懂]

    AjaxPro2完整入门教程[通俗易懂]网上关于AjaxPro的完整教程太少,所以这里我利用下自己的空余时间写一篇较为完整的AjaxPro教程,希望大家能够提出更多宝贵的建议

    2022年7月4日
    26
  • JAVA下载文件代码「建议收藏」

    JAVA下载文件代码「建议收藏」publicstaticHttpServletResponsedownload(Stringpath,HttpServletResponseresponse,StringfileName){try{//path是指欲下载的文件的路径。Filefile=newFile(path);…

    2022年7月8日
    20
  • 报关单上常出现的英文单词缩写是_报关单用英文怎么说

    报关单上常出现的英文单词缩写是_报关单用英文怎么说  一.单证(Documents)  进出口业务涉及的单证总的包括三大类:1。金融单证(信用证、汇票、支票和本票)  2.商业单证(发票、装箱单、运输单据、保险单等)3。用于政府管制的单证(许可证、原产地证明、商检证等) declarationform报关单 Threesteps—declaration,examinationofgoodsandreleaseofgoods,

    2022年9月21日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号