oc 扫码
2021-04-02 本文已影响0人
喵喵粉
- 使用相机扫码
- 扫描相册
1. 使用相机扫码
- 相机授权
- 用到
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
- 新建
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
- 使用
- (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");
}
}
}