558 lines
15 KiB
Objective-C
558 lines
15 KiB
Objective-C
//
|
||
// LBXScanBaseViewController.m
|
||
//
|
||
|
||
#import "LBXScanBaseViewController.h"
|
||
#import <AssetsLibrary/AssetsLibrary.h>
|
||
#import <Photos/Photos.h>
|
||
#import "ScanResultViewController.h"
|
||
//#import "LBXToast.h"
|
||
|
||
@interface LBXScanBaseViewController ()
|
||
|
||
@end
|
||
|
||
@implementation LBXScanBaseViewController
|
||
|
||
- (void)viewDidLoad {
|
||
[super viewDidLoad];
|
||
// Do any additional setup after loading the view.
|
||
if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) {
|
||
|
||
self.edgesForExtendedLayout = UIRectEdgeNone;
|
||
}
|
||
|
||
self.view.backgroundColor = [UIColor blackColor];
|
||
|
||
#if TARGET_IPHONE_SIMULATOR
|
||
|
||
self.view.backgroundColor = [UIColor whiteColor];
|
||
#else
|
||
|
||
#endif
|
||
|
||
|
||
self.firstLoad = YES;
|
||
}
|
||
|
||
- (void)viewWillAppear:(BOOL)animated
|
||
{
|
||
[super viewWillAppear:animated];
|
||
|
||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChanged:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
|
||
}
|
||
|
||
- (void)viewWillDisappear:(BOOL)animated
|
||
{
|
||
[super viewWillDisappear:animated];
|
||
[[NSNotificationCenter defaultCenter]removeObserver:self];
|
||
|
||
self.firstLoad = NO;
|
||
}
|
||
|
||
- (void)statusBarOrientationChanged:(NSNotification*)notification
|
||
{
|
||
|
||
}
|
||
|
||
|
||
|
||
#pragma mark- 识别结果
|
||
- (void)scanResultWithArray:(NSArray<LBXScanResult*>*)array
|
||
{
|
||
|
||
if (!array || array.count < 1)
|
||
{
|
||
NSLog(@"失败失败了。。。。");
|
||
NSLog(@"失败失败了。。。。");
|
||
NSLog(@"失败失败了。。。。");
|
||
|
||
if (!_continuous) {
|
||
[self reStartDevice];
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
//经测试,可以ZXing同时识别2个二维码,不能同时识别二维码和条形码
|
||
// for (LBXScanResult *result in array) {
|
||
//
|
||
// NSLog(@"scanResult:%@",result.strScanned);
|
||
// }
|
||
|
||
LBXScanResult *scanResult = array[0];
|
||
|
||
NSString*strResult = scanResult.strScanned;
|
||
|
||
|
||
if (_continuous) {
|
||
|
||
if (strResult) {
|
||
// [LBXToast showToastWithMessage:strResult];
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
if (!strResult) {
|
||
|
||
[self reStartDevice];
|
||
return;
|
||
}
|
||
|
||
[self.qRScanView stopScanAnimation];
|
||
|
||
self.scanImage = scanResult.imgScanned;
|
||
|
||
//TODO: 这里可以根据需要添加震动或播放成功提醒音等提示相关代码
|
||
//...
|
||
|
||
//TODO:表示二维码位置
|
||
//ZXing在开启区域识别后,当前计算方式不准确
|
||
if (!self.isOpenInterestRect && self.cameraPreView && !CGRectEqualToRect(CGRectZero, scanResult.bounds) ) {
|
||
|
||
CGFloat centerX = scanResult.bounds.origin.x + scanResult.bounds.size.width / 2;
|
||
CGFloat centerY = scanResult.bounds.origin.y + scanResult.bounds.size.height / 2;
|
||
|
||
//条码中心位置绘制红色正方形
|
||
[self signCodeWithCenterX:centerX centerY:centerY];
|
||
|
||
//条码位置边缘绘制及内部填充
|
||
[self didDetectCodes:scanResult.bounds corner:scanResult.corners];
|
||
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
// dispatch_async(dispatch_get_main_queue(), ^{
|
||
[self showNextVCWithScanResult:scanResult];
|
||
// });
|
||
});
|
||
}
|
||
else
|
||
{
|
||
[self showNextVCWithScanResult:scanResult];
|
||
}
|
||
|
||
}
|
||
|
||
-(UIImage *)getImageFromLayer:(CALayer *)layer size:(CGSize)size
|
||
{
|
||
UIGraphicsBeginImageContextWithOptions(size, YES, [[UIScreen mainScreen]scale]);
|
||
[layer renderInContext:UIGraphicsGetCurrentContext()];
|
||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||
UIGraphicsEndImageContext();
|
||
|
||
return image;
|
||
}
|
||
|
||
|
||
- (CGPoint)pointForCorner:(NSDictionary *)corner {
|
||
CGPoint point;
|
||
CGPointMakeWithDictionaryRepresentation((CFDictionaryRef)corner, &point);
|
||
return point;
|
||
}
|
||
|
||
|
||
|
||
- (void)handCorners:(NSArray<NSDictionary *> *)corners bounds:(CGRect)bounds
|
||
{
|
||
CGFloat totalX = 0;
|
||
CGFloat totalY = 0;
|
||
|
||
for (NSDictionary *dic in corners) {
|
||
CGPoint pt = [self pointForCorner:dic];
|
||
NSLog(@"pt:%@",NSStringFromCGPoint(pt));
|
||
totalX += pt.x;
|
||
totalY += pt.y;
|
||
}
|
||
|
||
CGFloat averX = totalX / corners.count;
|
||
CGFloat averY = totalY / corners.count;
|
||
|
||
|
||
|
||
CGFloat minSize = MIN(bounds.size.width , bounds.size.height);
|
||
|
||
NSLog(@"averx:%f,avery:%f minsize:%f",averX,averY,minSize);
|
||
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
|
||
[self signCodeWithCenterX:averX centerY:averY];
|
||
|
||
});
|
||
}
|
||
|
||
- (void)signCodeWithCenterX:(CGFloat)centerX centerY:(CGFloat)centerY
|
||
{
|
||
UIView *signView = [[UIView alloc]initWithFrame:CGRectMake(centerX-10, centerY-10, 20, 20)];
|
||
|
||
[self.cameraPreView addSubview:signView];
|
||
signView.backgroundColor = [UIColor redColor];
|
||
|
||
self.codeFlagView = signView;
|
||
}
|
||
|
||
|
||
|
||
//继承者实现
|
||
- (void)reStartDevice
|
||
{
|
||
|
||
}
|
||
|
||
- (void)resetCodeFlagView
|
||
{
|
||
if (_codeFlagView) {
|
||
[_codeFlagView removeFromSuperview];
|
||
self.codeFlagView = nil;
|
||
}
|
||
if (self.layers) {
|
||
|
||
for (CALayer *layer in self.layers) {
|
||
[layer removeFromSuperlayer];
|
||
}
|
||
|
||
self.layers = nil;
|
||
}
|
||
}
|
||
|
||
- (UIImage *)imageByCroppingWithSrcImage:(UIImage*)srcImg cropRect:(CGRect)cropRect
|
||
{
|
||
|
||
CGImageRef imageRef = srcImg.CGImage;
|
||
CGImageRef imagePartRef = CGImageCreateWithImageInRect(imageRef, cropRect);
|
||
UIImage *cropImage = [UIImage imageWithCGImage:imagePartRef];
|
||
CGImageRelease(imagePartRef);
|
||
return cropImage;
|
||
}
|
||
|
||
|
||
- (void)showNextVCWithScanResult:(LBXScanResult*)strResult
|
||
{
|
||
|
||
if (_continuous) {
|
||
|
||
}else
|
||
{
|
||
|
||
ScanResultViewController *vc = [ScanResultViewController new];
|
||
vc.imgScan = strResult.imgScanned;
|
||
|
||
vc.strScan = strResult.strScanned;
|
||
|
||
vc.strCodeType = strResult.strBarCodeType;
|
||
|
||
[self.navigationController pushViewController:vc animated:YES];
|
||
|
||
//隐藏标记条码位置的信息
|
||
[self resetCodeFlagView];
|
||
}
|
||
|
||
}
|
||
|
||
|
||
#pragma mark- 绘制二维码区域标志
|
||
- (void)didDetectCodes:(CGRect)bounds corner:(NSArray<NSDictionary*>*)corners
|
||
{
|
||
AVCaptureVideoPreviewLayer * preview = nil;
|
||
|
||
for (CALayer *layer in [self.cameraPreView.layer sublayers]) {
|
||
|
||
if ( [layer isKindOfClass:[AVCaptureVideoPreviewLayer class]]) {
|
||
|
||
preview = (AVCaptureVideoPreviewLayer*)layer;
|
||
}
|
||
}
|
||
|
||
NSArray *layers = nil;
|
||
if (!layers) {
|
||
layers = @[[self makeBoundsLayer],[self makeCornersLayer]];
|
||
[preview addSublayer:layers[0]];
|
||
[preview addSublayer:layers[1]];
|
||
}
|
||
|
||
CAShapeLayer *boundsLayer = layers[0];
|
||
boundsLayer.path = [self bezierPathForBounds:bounds].CGPath;
|
||
//得到一个CGPathRef赋给图层的path属性
|
||
|
||
if (corners) {
|
||
CAShapeLayer *cornersLayer = layers[1];
|
||
cornersLayer.path = [self bezierPathForCorners:corners].CGPath;
|
||
//对于cornersLayer,基于元数据对象创建一个CGPath
|
||
}
|
||
|
||
self.layers = layers;
|
||
|
||
}
|
||
|
||
|
||
- (UIBezierPath *)bezierPathForBounds:(CGRect)bounds {
|
||
// 图层边界,创建一个和对象的bounds关联的UIBezierPath
|
||
return [UIBezierPath bezierPathWithRect:bounds];
|
||
}
|
||
|
||
- (CAShapeLayer *)makeBoundsLayer {
|
||
//CAShapeLayer 是具体化的CALayer子类,用于绘制Bezier路径
|
||
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
|
||
shapeLayer.strokeColor = [UIColor colorWithRed:0.96f green:0.75f blue:0.06f alpha:1.0f].CGColor;
|
||
shapeLayer.fillColor = nil;
|
||
shapeLayer.lineWidth = 4.0f;
|
||
|
||
return shapeLayer;
|
||
}
|
||
|
||
- (CAShapeLayer *)makeCornersLayer {
|
||
|
||
CAShapeLayer *cornersLayer = [CAShapeLayer layer];
|
||
cornersLayer.lineWidth = 2.0f;
|
||
cornersLayer.strokeColor = [UIColor colorWithRed:0.172 green:0.671 blue:0.428 alpha:1.0].CGColor;
|
||
cornersLayer.fillColor = [UIColor colorWithRed:0.190 green:0.753 blue:0.489 alpha:0.5].CGColor;
|
||
|
||
return cornersLayer;;
|
||
}
|
||
|
||
- (UIBezierPath *)bezierPathForCorners:(NSArray *)corners {
|
||
|
||
UIBezierPath *path = [UIBezierPath bezierPath];
|
||
for (int i = 0; i < corners.count; i ++) {
|
||
CGPoint point = [self pointForCorner:corners[i]];
|
||
//遍历每个条目,为每个条目创建一个CGPoint
|
||
if (i == 0) {
|
||
[path moveToPoint:point];
|
||
} else {
|
||
[path addLineToPoint:point];
|
||
}
|
||
}
|
||
[path closePath];
|
||
return path;
|
||
}
|
||
|
||
|
||
#pragma mark- 相册
|
||
|
||
//继承者实现
|
||
- (void)recognizeImageWithImage:(UIImage*)image
|
||
{
|
||
|
||
|
||
}
|
||
|
||
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
|
||
{
|
||
__block UIImage* image = [info objectForKey:UIImagePickerControllerEditedImage];
|
||
|
||
if (!image){
|
||
image = [info objectForKey:UIImagePickerControllerOriginalImage];
|
||
}
|
||
|
||
[picker dismissViewControllerAnimated:YES completion:^{
|
||
[self recognizeImageWithImage:image];
|
||
}];
|
||
}
|
||
|
||
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
|
||
{
|
||
NSLog(@"cancel");
|
||
|
||
[picker dismissViewControllerAnimated:YES completion:nil];
|
||
}
|
||
|
||
|
||
#pragma mark- 权限
|
||
- (void)requestCameraPemissionWithResult:(void(^)( BOOL granted))completion
|
||
{
|
||
if ([AVCaptureDevice respondsToSelector:@selector(authorizationStatusForMediaType:)])
|
||
{
|
||
AVAuthorizationStatus permission =
|
||
[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
||
|
||
switch (permission) {
|
||
case AVAuthorizationStatusAuthorized:
|
||
completion(YES);
|
||
break;
|
||
case AVAuthorizationStatusDenied:
|
||
case AVAuthorizationStatusRestricted:
|
||
completion(NO);
|
||
break;
|
||
case AVAuthorizationStatusNotDetermined:
|
||
{
|
||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
|
||
completionHandler:^(BOOL granted) {
|
||
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
if (granted) {
|
||
completion(true);
|
||
} else {
|
||
completion(false);
|
||
}
|
||
});
|
||
|
||
}];
|
||
}
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|
||
+ (void)authorizePhotoPermissionWithCompletion:(void(^)(BOOL granted,BOOL firstTime))completion
|
||
{
|
||
if (@available(iOS 8.0, *)) {
|
||
|
||
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
|
||
|
||
switch (status) {
|
||
case PHAuthorizationStatusAuthorized:
|
||
{
|
||
if (completion) {
|
||
completion(YES,NO);
|
||
}
|
||
}
|
||
break;
|
||
case PHAuthorizationStatusRestricted:
|
||
case PHAuthorizationStatusDenied:
|
||
{
|
||
if (completion) {
|
||
completion(NO,NO);
|
||
}
|
||
}
|
||
break;
|
||
case PHAuthorizationStatusNotDetermined:
|
||
{
|
||
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
|
||
if (completion) {
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
completion(status == PHAuthorizationStatusAuthorized,YES);
|
||
});
|
||
}
|
||
}];
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
if (completion) {
|
||
completion(NO,NO);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
}else{
|
||
|
||
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
|
||
switch (status) {
|
||
case ALAuthorizationStatusAuthorized:
|
||
{
|
||
if (completion) {
|
||
completion(YES, NO);
|
||
}
|
||
}
|
||
break;
|
||
case ALAuthorizationStatusNotDetermined:
|
||
{
|
||
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
|
||
|
||
[library enumerateGroupsWithTypes:ALAssetsGroupAll
|
||
usingBlock:^(ALAssetsGroup *assetGroup, BOOL *stop) {
|
||
if (*stop) {
|
||
if (completion) {
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
completion(YES, NO);
|
||
});
|
||
|
||
}
|
||
} else {
|
||
*stop = YES;
|
||
}
|
||
}
|
||
failureBlock:^(NSError *error) {
|
||
if (completion) {
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
completion(NO, YES);
|
||
});
|
||
}
|
||
}];
|
||
} break;
|
||
case ALAuthorizationStatusRestricted:
|
||
case ALAuthorizationStatusDenied:
|
||
{
|
||
if (completion) {
|
||
completion(NO, NO);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
- (BOOL)isLandScape
|
||
{
|
||
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
|
||
|
||
BOOL landScape = NO;
|
||
|
||
|
||
switch (orientation) {
|
||
case UIDeviceOrientationPortrait: {
|
||
landScape = NO;
|
||
}
|
||
break;
|
||
case UIDeviceOrientationLandscapeLeft: {
|
||
landScape = YES;
|
||
}
|
||
break;
|
||
case UIDeviceOrientationLandscapeRight: {
|
||
|
||
landScape = YES;
|
||
}
|
||
break;
|
||
case UIDeviceOrientationPortraitUpsideDown: {
|
||
|
||
landScape = NO;
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return landScape;
|
||
|
||
}
|
||
|
||
- (AVCaptureVideoOrientation)videoOrientation
|
||
{
|
||
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
|
||
|
||
|
||
switch (orientation) {
|
||
case UIDeviceOrientationPortrait: {
|
||
return AVCaptureVideoOrientationPortrait;
|
||
}
|
||
break;
|
||
case UIDeviceOrientationLandscapeRight : {
|
||
return AVCaptureVideoOrientationLandscapeLeft;
|
||
}
|
||
break;
|
||
case UIDeviceOrientationLandscapeLeft: {
|
||
return AVCaptureVideoOrientationLandscapeRight;
|
||
|
||
}
|
||
break;
|
||
case UIDeviceOrientationPortraitUpsideDown: {
|
||
return AVCaptureVideoOrientationPortraitUpsideDown;
|
||
|
||
}
|
||
break;
|
||
default:
|
||
return AVCaptureVideoOrientationPortrait;
|
||
break;
|
||
}
|
||
|
||
return AVCaptureVideoOrientationPortrait;
|
||
}
|
||
|
||
@end
|