oc 扫码

2021-04-02  本文已影响0人  喵喵粉
  1. 使用相机扫码
  2. 扫描相册

1. 使用相机扫码

  1. 相机授权
  2. 用到UIView的扩展
    UIViewExt.h
#import <UIKit/UIKit.h>

CGPoint CGRectGetCenter(CGRect rect);
CGRect  CGRectMoveToCenter(CGRect rect, CGPoint center);

@interface UIView (ViewFrameGeometry)
@property CGPoint origin;
@property CGSize size;

@property (readonly) CGPoint bottomLeft;
@property (readonly) CGPoint bottomRight;
@property (readonly) CGPoint topRight;

@property CGFloat height;
@property CGFloat width;

@property CGFloat top;
@property CGFloat left;

@property CGFloat bottom;
@property CGFloat right;

- (void) moveBy: (CGPoint) delta;
- (void) scaleBy: (CGFloat) scaleFactor;
- (void) fitInSize: (CGSize) aSize;
- (UIViewController *)viewController;
@end

UIViewExt.m

CGPoint CGRectGetCenter(CGRect rect)
{
    CGPoint pt;
    pt.x = CGRectGetMidX(rect);
    pt.y = CGRectGetMidY(rect);
    return pt;
}

CGRect CGRectMoveToCenter(CGRect rect, CGPoint center)
{
    CGRect newrect = CGRectZero;
    newrect.origin.x = center.x-CGRectGetMidX(rect);
    newrect.origin.y = center.y-CGRectGetMidY(rect);
    newrect.size = rect.size;
    return newrect;
}

@implementation UIView (ViewGeometry)

// Retrieve and set the origin
- (CGPoint) origin
{
    return self.frame.origin;
}

- (void) setOrigin: (CGPoint) aPoint
{
    CGRect newframe = self.frame;
    newframe.origin = aPoint;
    self.frame = newframe;
}


// Retrieve and set the size
- (CGSize) size
{
    return self.frame.size;
}

- (void) setSize: (CGSize) aSize
{
    CGRect newframe = self.frame;
    newframe.size = aSize;
    self.frame = newframe;
}

// Query other frame locations
- (CGPoint) bottomRight
{
    CGFloat x = self.frame.origin.x + self.frame.size.width;
    CGFloat y = self.frame.origin.y + self.frame.size.height;
    return CGPointMake(x, y);
}

- (CGPoint) bottomLeft
{
    CGFloat x = self.frame.origin.x;
    CGFloat y = self.frame.origin.y + self.frame.size.height;
    return CGPointMake(x, y);
}

- (CGPoint) topRight
{
    CGFloat x = self.frame.origin.x + self.frame.size.width;
    CGFloat y = self.frame.origin.y;
    return CGPointMake(x, y);
}


// Retrieve and set height, width, top, bottom, left, right
- (CGFloat) height
{
    return self.frame.size.height;
}

- (void) setHeight: (CGFloat) newheight
{
    CGRect newframe = self.frame;
    newframe.size.height = newheight;
    self.frame = newframe;
}

- (CGFloat) width
{
    return self.frame.size.width;
}

- (void) setWidth: (CGFloat) newwidth
{
    CGRect newframe = self.frame;
    newframe.size.width = newwidth;
    self.frame = newframe;
}

- (CGFloat) top
{
    return self.frame.origin.y;
}

- (void) setTop: (CGFloat) newtop
{
    CGRect newframe = self.frame;
    newframe.origin.y = newtop;
    self.frame = newframe;
}

- (CGFloat) left
{
    return self.frame.origin.x;
}

- (void) setLeft: (CGFloat) newleft
{
    CGRect newframe = self.frame;
    newframe.origin.x = newleft;
    self.frame = newframe;
}

- (CGFloat) bottom
{
    return self.frame.origin.y + self.frame.size.height;
}

- (void) setBottom: (CGFloat) newbottom
{
    CGRect newframe = self.frame;
    newframe.origin.y = newbottom - self.frame.size.height;
    self.frame = newframe;
}

- (CGFloat) right
{
    return self.frame.origin.x + self.frame.size.width;
}

- (void) setRight: (CGFloat) newright
{
    CGFloat delta = newright - (self.frame.origin.x + self.frame.size.width);
    CGRect newframe = self.frame;
    newframe.origin.x += delta ;
    self.frame = newframe;
}

// Move via offset
- (void) moveBy: (CGPoint) delta
{
    CGPoint newcenter = self.center;
    newcenter.x += delta.x;
    newcenter.y += delta.y;
    self.center = newcenter;
}

// Scaling
- (void) scaleBy: (CGFloat) scaleFactor
{
    CGRect newframe = self.frame;
    newframe.size.width *= scaleFactor;
    newframe.size.height *= scaleFactor;
    self.frame = newframe;
}

// Ensure that both dimensions fit within the given size by scaling down
- (void) fitInSize: (CGSize) aSize
{
    CGFloat scale;
    CGRect newframe = self.frame;
    
    if (newframe.size.height && (newframe.size.height > aSize.height))
    {
        scale = aSize.height / newframe.size.height;
        newframe.size.width *= scale;
        newframe.size.height *= scale;
    }
    
    if (newframe.size.width && (newframe.size.width >= aSize.width))
    {
        scale = aSize.width / newframe.size.width;
        newframe.size.width *= scale;
        newframe.size.height *= scale;
    }                                                           
    
    self.frame = newframe;  
}
- (UIViewController *)viewController
{
    //获得下一个事件响应者
    UIResponder *next = [self nextResponder];
    
    do {
        if ([next isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)next;
        }
        
        next = [next nextResponder];
        
    } while (next != nil);
    
    return nil;
}
@end
  1. 新建vc:ScanQRCodeVC
    ScanQRCodeVC.h
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

//typedef void (^DoneBlock)(NSString *code);
//@property (nonatomic, copy) DoneBlock doneBlock;

@interface ScanQRCodeVC : UIViewController

- (instancetype)initWithScanDone:(void (^)(NSString *code))done;

@end

NS_ASSUME_NONNULL_END

ScanQRCodeVC.m

#import "ScanQRCodeVC.h"
#import <AVFoundation/AVFoundation.h>
#import "UIViewExt.h"
#import "CameraPrivateObj.h"

@interface ScanQRCodeVC ()<AVCaptureMetadataOutputObjectsDelegate>
@property (nonatomic, strong) AVCaptureDevice *device;
@property (nonatomic, strong) AVCaptureDeviceInput *input;
@property (nonatomic, strong) AVCaptureMetadataOutput *output;
@property (nonatomic, strong) AVCaptureSession *session;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *preview;

@property (nonatomic, strong) UIImageView *ivRedLine;
@property (nonatomic, assign) NSInteger count;

@property (nonatomic, copy) void (^doneBlock)(NSString *);
@end

@implementation ScanQRCodeVC

- (instancetype)initWithScanDone:(void (^)(NSString *code))done {
    if (self = [super initWithNibName:nil bundle:nil]) {
        self.doneBlock = done;
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.view.backgroundColor = [UIColor blackColor];
    
    [self cameraAuth];
    [self setupUI];
}

#pragma mark - init

- (void)cameraAuth {
    [CameraPrivateObj extCameraPermissions:^{
        [self setupCamera];
    } failed:^(NSString * _Nonnull desc) {
        NSLog(@"%@", desc);
    } deniedBlock:^{
        NSString *tips = NSLocalizedString(@"AVAuthorization", @"您没有权限访问相机");
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:tips message:nil preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
            // 点击取消
        }]];
        [alert addAction:[UIAlertAction actionWithTitle:@"去设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            // 点击确定
            if (@available(iOS 10.0, *)) {
                [UIApplication.sharedApplication openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
            } else {
                [UIApplication.sharedApplication openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
            }
        }]];
        [self presentViewController:alert animated:YES completion:nil];
    }];
}

- (void)setupUI {
    CGFloat kScreenWidth = UIScreen.mainScreen.bounds.size.width;
    CGFloat kScreenHeight = UIScreen.mainScreen.bounds.size.height;
    CGFloat kStateBarHeight = CGRectGetHeight([UIApplication sharedApplication].statusBarFrame);
    CGFloat kNavBarHeight = 44;
    CGFloat kWidthRation = (kScreenWidth/320.f);
    CGFloat scanWidth = 250.f;
    
    CGPoint center = CGPointMake(kScreenWidth/2.f, kStateBarHeight +kNavBarHeight +30*kWidthRation+scanWidth/2.f);
    UIImageView *barImage1 = [[UIImageView alloc]initWithFrame:CGRectMake(center.x-scanWidth/2.f, center.y-scanWidth/2.f, 25, 25)];
    barImage1.image = [UIImage imageNamed:@"img_bar1.png"];
    [self.view addSubview:barImage1];
    
    UIImageView *barImage2 = [[UIImageView alloc]initWithFrame:CGRectMake(center.x+scanWidth/2.f-25, center.y-scanWidth/2.f, 25, 25)];
    barImage2.image = [UIImage imageNamed:@"img_bar2.png"];
    [self.view addSubview:barImage2];

    UIImageView *barImage3 = [[UIImageView alloc]initWithFrame:CGRectMake(center.x-scanWidth/2.f, center.y+scanWidth/2.f-25, 25, 25)];
    barImage3.image = [UIImage imageNamed:@"img_bar3.png"];
    [self.view addSubview:barImage3];

    UIImageView *barImage4 = [[UIImageView alloc]initWithFrame:CGRectMake(center.x+scanWidth/2.f-25, center.y+scanWidth/2.f-25, 25, 25)];
    barImage4.image = [UIImage imageNamed:@"img_bar4.png"];
    [self.view addSubview:barImage4];

    _ivRedLine = [[UIImageView alloc]initWithFrame:CGRectMake(center.x-240/2.f, center.y - scanWidth/2.f+5, 240, 5)];
    _ivRedLine.image = [UIImage imageNamed:@"img_RQcode_line.png"];
    _ivRedLine.hidden = YES;
    [self.view addSubview:_ivRedLine];
    
    UIView *viewO = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.width, barImage1.top)];
    viewO.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.7];
    [self.view addSubview:viewO];
    
    UIView *viewT = [[UIView alloc]initWithFrame:CGRectMake(0, barImage1.top, barImage1.left, scanWidth)];
    viewT.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.7];
    [self.view addSubview:viewT];
    
    UIView *viewS = [[UIView alloc]initWithFrame:CGRectMake(barImage2.right, barImage1.top, kScreenWidth - barImage2.right, scanWidth)];
    viewS.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.7];
    [self.view addSubview:viewS];
    
    UIView *viewF = [[UIView alloc]initWithFrame:CGRectMake(0, barImage3.bottom, kScreenWidth, kScreenHeight-barImage3.bottom)];
    viewF.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.7];
    [self.view addSubview:viewF];
    
    
    // line移动的范围为 一个扫码框的高度(由于图片问题再减去图片的高度)
    CABasicAnimation * lineAnimation = [self animationWith:@(0) toValue:@(scanWidth-15) repCount:MAXFLOAT duration:1.5f];
    [_ivRedLine.layer addAnimation:lineAnimation forKey:@"LineImgViewAnimation"];
    
//    dispatch_async(dispatch_get_global_queue(0, 0), ^{
//        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
//        dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
//            [self setupCamera];
//        });
//    });
}

- (void)statCamera {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
            [self setupCamera];
        });
    });
}

#pragma mark - 扫码line滑动动画
- (CABasicAnimation*)animationWith:(id)fromValue toValue:(id)toValue repCount:(CGFloat)repCount duration:(CGFloat)duration {
    
    CABasicAnimation *lineAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    lineAnimation.fromValue = fromValue;
    lineAnimation.toValue = toValue;
    lineAnimation.repeatCount = repCount;
    lineAnimation.duration = duration;
    lineAnimation.fillMode = kCAFillModeForwards;
    lineAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    lineAnimation.removedOnCompletion = NO;
    
    return lineAnimation;
}
//暂停动画
- (void)pauseAnimation {
    //(0-5)
    CFTimeInterval pauseTime = [_ivRedLine.layer convertTime:CACurrentMediaTime() fromLayer:nil];
    _ivRedLine.layer.timeOffset = pauseTime;
    _ivRedLine.layer.speed = 0;
}
-(void)backAction{
    [self.navigationController popViewControllerAnimated:YES];
    [_session stopRunning];
    _ivRedLine = nil;
}

- (void)setupCamera {
    _ivRedLine.hidden = NO;
    // Device
    _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    // Input
    _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
    
    // Output
    _output = [[AVCaptureMetadataOutput alloc]init];
    [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    
    // Session
    _session = [[AVCaptureSession alloc]init];
    [_session setSessionPreset:AVCaptureSessionPresetHigh];
    if ([_session canAddInput:self.input])
    {
        [_session addInput:self.input];
    }
    
    if ([_session canAddOutput:self.output])
    {
        [_session addOutput:self.output];
    }
    
    // 条码类型 AVMetadataObjectTypeQRCode
    _output.metadataObjectTypes =@[AVMetadataObjectTypeUPCECode,
                                   AVMetadataObjectTypeCode39Code,
                                   AVMetadataObjectTypeCode39Mod43Code,
                                   AVMetadataObjectTypeEAN13Code,
                                   AVMetadataObjectTypeEAN8Code,
                                   AVMetadataObjectTypeCode93Code,
                                   AVMetadataObjectTypeCode128Code,
                                   AVMetadataObjectTypePDF417Code,
                                   AVMetadataObjectTypeQRCode,
                                   AVMetadataObjectTypeAztecCode];
    CGFloat kScreenWidth = UIScreen.mainScreen.bounds.size.width;
    CGFloat kScreenHeight = UIScreen.mainScreen.bounds.size.height;
    [_output setRectOfInterest:CGRectMake((64+20)/kScreenHeight, ((kScreenWidth-240)/2)/kScreenWidth, 240/kScreenHeight, 240/kScreenWidth)];
    // Preview
    _preview =[AVCaptureVideoPreviewLayer layerWithSession:self.session];
    _preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
 
    _preview.frame = self.view.layer.bounds;
    [self.view.layer insertSublayer:self.preview atIndex:0];
    // Start
    [_session startRunning];
}


#pragma mark - AVCaptureMetadataOutputObjectsDelegate

- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    [_session stopRunning];
    
    [self pauseAnimation];
    NSString *stringValue = @"";
    
    if ([metadataObjects count] >0)
    {
        AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];
        stringValue = [NSString stringWithFormat:@"%@", metadataObject.stringValue];
    }
    
    if (self.count>0) {
        return;
    }

    _count++;
    
    NSLog(@"%@ count:%ld", stringValue, (long)_count);
    
    if (self.doneBlock) {
        self.doneBlock(stringValue);
    }
    
    [self.navigationController popViewControllerAnimated:YES];
}


@end
  1. 使用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//    ScanQRCodeVC *vc = [ScanQRCodeVC new];
//    vc.doneBlock = ^(NSString * _Nonnull code) {
//        NSLog(@"扫码的code:%@", code);
//    };
    
    ScanQRCodeVC *vc = [[ScanQRCodeVC alloc] initWithScanDone:^(NSString * _Nonnull code) {
        NSLog(@"扫码的code:%@", code);
    }];
    [self.navigationController pushViewController:vc animated:YES];
}

2. 扫描相册

- (void)scanLocalDemo {
    [CameraPrivateObj extPhotoPermissions:^{
        [self scanFromImage:[UIImage imageNamed:@"abd"]];
    } failed:^(NSString * _Nonnull desc) {
        NSLog(@"%@", desc);
    } deniedBlock:^{
        NSLog(@"denied");
    }];
}

- (void)scanFromImage:(UIImage *)image {
    //
    NSData *data = UIImageJPEGRepresentation(image, 1);
    CIImage *ciImage = [CIImage imageWithData:data];
    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh, CIDetectorImageOrientation:@1}];
    NSArray<CIFeature *> *features = [detector featuresInImage:ciImage];
    for (CIFeature *feature in features) {
        NSLog(@"%@", feature);
        
        if ([feature isKindOfClass:[CIQRCodeFeature class]]) {
            CIQRCodeFeature *ft = (CIQRCodeFeature *)feature;
            NSLog(@"二维码:%@", ft.messageString);
        } else if ([feature isKindOfClass:[CITextFeature class]]) {
            CITextFeature *ft = (CITextFeature *)feature;
            NSLog(@"文本:%@", ft.subFeatures);
        } else {
            NSLog(@"other");
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读