123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624 |
- #import "LBXScanNative.h"
- @interface LBXScanNative()<AVCaptureMetadataOutputObjectsDelegate>
- {
- BOOL bNeedScanResult;
- }
- @property (assign,nonatomic)AVCaptureDevice * device;
- @property (strong,nonatomic)AVCaptureDeviceInput * input;
- @property (strong,nonatomic)AVCaptureMetadataOutput * output;
- @property (strong,nonatomic)AVCaptureSession * session;
- @property (strong,nonatomic)AVCaptureVideoPreviewLayer * preview;
- @property(nonatomic,strong) AVCaptureStillImageOutput *stillImageOutput;//拍照
- @property(nonatomic,assign)BOOL isNeedCaputureImage;
- //扫码结果
- @property (nonatomic, strong) NSMutableArray<LBXScanResult*> *arrayResult;
- //扫码类型
- @property (nonatomic, strong) NSArray* arrayBarCodeType;
- /**
- @brief 视频预览显示视图
- */
- @property (nonatomic,weak)UIView *videoPreView;
- /*!
- * 扫码结果返回
- */
- @property(nonatomic,copy)void (^blockScanResult)(NSArray<LBXScanResult*> *array);
- @end
- @implementation LBXScanNative
- - (void)setNeedCaptureImage:(BOOL)isNeedCaputureImg
- {
- _isNeedCaputureImage = isNeedCaputureImg;
- }
- - (instancetype)initWithPreView:(UIView*)preView ObjectType:(NSArray*)objType cropRect:(CGRect)cropRect success:(void(^)(NSArray<LBXScanResult*> *array))block
- {
- if (self = [super init]) {
- [self initParaWithPreView:preView ObjectType:objType cropRect:cropRect success:block];
- }
- return self;
- }
- - (instancetype)initWithPreView:(UIView*)preView ObjectType:(NSArray*)objType success:(void(^)(NSArray<LBXScanResult*> *array))block
- {
- if (self = [super init]) {
-
- [self initParaWithPreView:preView ObjectType:objType cropRect:CGRectZero success:block];
- }
-
- return self;
- }
- - (void)initParaWithPreView:(UIView*)videoPreView ObjectType:(NSArray*)objType cropRect:(CGRect)cropRect success:(void(^)(NSArray<LBXScanResult*> *array))block
- {
- self.arrayBarCodeType = objType;
- self.blockScanResult = block;
- self.videoPreView = videoPreView;
-
- _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
-
- if (!_device) {
- return;
- }
-
- // Input
- _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
- if ( !_input )
- return ;
-
-
- bNeedScanResult = YES;
-
- // Output
- _output = [[AVCaptureMetadataOutput alloc]init];
- [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
-
-
- if ( !CGRectEqualToRect(cropRect,CGRectZero) )
- {
- _output.rectOfInterest = cropRect;
- }
-
- /*
- // Setup the still image file output
- */
- // AVCapturePhotoOutput
-
- _stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
- NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
- AVVideoCodecJPEG, AVVideoCodecKey,
- nil];
- [_stillImageOutput setOutputSettings:outputSettings];
-
- // Session
- _session = [[AVCaptureSession alloc]init];
- [_session setSessionPreset:AVCaptureSessionPresetHigh];
-
- // _session.
-
- // videoScaleAndCropFactor
-
- if ([_session canAddInput:_input])
- {
- [_session addInput:_input];
- }
-
- if ([_session canAddOutput:_output])
- {
- [_session addOutput:_output];
- }
- if ([_session canAddOutput:_stillImageOutput])
- {
- [_session addOutput:_stillImageOutput];
- }
-
-
-
-
- // 条码类型 AVMetadataObjectTypeQRCode
- // _output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode];
-
- if (!objType) {
- objType = [self defaultMetaDataObjectTypes];
- }
-
- _output.metadataObjectTypes = objType;
-
- // Preview
- _preview =[AVCaptureVideoPreviewLayer layerWithSession:_session];
- _preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
-
- //_preview.frame =CGRectMake(20,110,280,280);
-
- CGRect frame = videoPreView.frame;
- frame.origin = CGPointZero;
- _preview.frame = frame;
-
- [videoPreView.layer insertSublayer:self.preview atIndex:0];
-
-
-
- AVCaptureConnection *videoConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]];
- // CGFloat maxScale = videoConnection.videoMaxScaleAndCropFactor;
- CGFloat scale = videoConnection.videoScaleAndCropFactor;
- NSLog(@"%f",scale);
- // CGFloat zoom = maxScale / 50;
- // if (zoom < 1.0f || zoom > maxScale)
- // {
- // return;
- // }
- // videoConnection.videoScaleAndCropFactor += zoom;
- // CGAffineTransform transform = videoPreView.transform;
- // videoPreView.transform = CGAffineTransformScale(transform, zoom, zoom);
-
-
- //先进行判断是否支持控制对焦,不开启自动对焦功能,很难识别二维码。
- if (_device.isFocusPointOfInterestSupported &&[_device isFocusModeSupported:AVCaptureFocusModeAutoFocus])
- {
- [_input.device lockForConfiguration:nil];
- [_input.device setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
- [_input.device unlockForConfiguration];
- }
- }
- - (CGFloat)getVideoMaxScale
- {
- [_input.device lockForConfiguration:nil];
- AVCaptureConnection *videoConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]];
- CGFloat maxScale = videoConnection.videoMaxScaleAndCropFactor;
- [_input.device unlockForConfiguration];
-
- return maxScale;
- }
- - (void)setVideoScale:(CGFloat)scale
- {
- [_input.device lockForConfiguration:nil];
-
- AVCaptureConnection *videoConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]];
-
- CGFloat zoom = scale / videoConnection.videoScaleAndCropFactor;
-
- videoConnection.videoScaleAndCropFactor = scale;
-
- [_input.device unlockForConfiguration];
-
- CGAffineTransform transform = _videoPreView.transform;
-
- _videoPreView.transform = CGAffineTransformScale(transform, zoom, zoom);
- }
- - (void)setScanRect:(CGRect)scanRect
- {
- //识别区域设置
- if (_output) {
- _output.rectOfInterest = [self.preview metadataOutputRectOfInterestForRect:scanRect];
- }
-
- }
- - (void)changeScanType:(NSArray*)objType
- {
- _output.metadataObjectTypes = objType;
- }
- - (void)startScan
- {
- if ( _input && !_session.isRunning )
- {
- [_session startRunning];
- bNeedScanResult = YES;
-
- [_videoPreView.layer insertSublayer:self.preview atIndex:0];
-
- // [_input.device addObserver:self forKeyPath:@"torchMode" options:0 context:nil];
- }
- bNeedScanResult = YES;
- }
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
- {
- if ( object == _input.device ) {
-
- NSLog(@"flash change");
- }
- }
- - (void)stopScan
- {
- bNeedScanResult = NO;
- if ( _input && _session.isRunning )
- {
- bNeedScanResult = NO;
- [_session stopRunning];
-
- // [self.preview removeFromSuperlayer];
- }
- }
- - (void)setTorch:(BOOL)torch {
-
- [self.input.device lockForConfiguration:nil];
- self.input.device.torchMode = torch ? AVCaptureTorchModeOn : AVCaptureTorchModeOff;
- [self.input.device unlockForConfiguration];
- }
- - (void)changeTorch
- {
- AVCaptureTorchMode torch = self.input.device.torchMode;
-
- switch (_input.device.torchMode) {
- case AVCaptureTorchModeAuto:
- break;
- case AVCaptureTorchModeOff:
- torch = AVCaptureTorchModeOn;
- break;
- case AVCaptureTorchModeOn:
- torch = AVCaptureTorchModeOff;
- break;
- default:
- break;
- }
-
- [_input.device lockForConfiguration:nil];
- _input.device.torchMode = torch;
- [_input.device unlockForConfiguration];
- }
- -(UIImage *)getImageFromLayer:(CALayer *)layer size:(CGSize)size
- {
- UIGraphicsBeginImageContextWithOptions(size, YES, [[UIScreen mainScreen]scale]);
- [layer renderInContext:UIGraphicsGetCurrentContext()];
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- return image;
- }
- - (AVCaptureConnection *)connectionWithMediaType:(NSString *)mediaType fromConnections:(NSArray *)connections
- {
- for ( AVCaptureConnection *connection in connections ) {
- for ( AVCaptureInputPort *port in [connection inputPorts] ) {
- if ( [[port mediaType] isEqual:mediaType] ) {
- return connection;
- }
- }
- }
- return nil;
- }
- - (void)captureImage
- {
- AVCaptureConnection *stillImageConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]];
-
-
- [[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:stillImageConnection
- completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error)
- {
- [self stopScan];
-
- if (imageDataSampleBuffer)
- {
- NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
-
- UIImage *img = [UIImage imageWithData:imageData];
-
- for (LBXScanResult* result in _arrayResult) {
-
- result.imgScanned = img;
- }
- }
-
- if (_blockScanResult)
- {
- _blockScanResult(_arrayResult);
- }
-
- }];
- }
- #pragma mark AVCaptureMetadataOutputObjectsDelegate
- - (void)captureOutput2:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
- {
-
-
- //识别扫码类型
- for(AVMetadataObject *current in metadataObjects)
- {
- if ([current isKindOfClass:[AVMetadataMachineReadableCodeObject class]] )
- {
-
- NSString *scannedResult = [(AVMetadataMachineReadableCodeObject *) current stringValue];
- NSLog(@"type:%@",current.type);
- NSLog(@"result:%@",scannedResult);
-
-
-
-
-
- //测试可以同时识别多个二维码
- }
- }
-
-
-
- }
- - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
- {
- if (!bNeedScanResult) {
- return;
- }
-
- bNeedScanResult = NO;
-
- if (!_arrayResult) {
-
- self.arrayResult = [NSMutableArray arrayWithCapacity:1];
- }
- else
- {
- [_arrayResult removeAllObjects];
- }
-
- //识别扫码类型
- for(AVMetadataObject *current in metadataObjects)
- {
- if ([current isKindOfClass:[AVMetadataMachineReadableCodeObject class]] )
- {
- bNeedScanResult = NO;
-
- NSLog(@"type:%@",current.type);
- NSString *scannedResult = [(AVMetadataMachineReadableCodeObject *) current stringValue];
-
- if (scannedResult && ![scannedResult isEqualToString:@""])
- {
- LBXScanResult *result = [LBXScanResult new];
- result.strScanned = scannedResult;
- result.strBarCodeType = current.type;
-
- [_arrayResult addObject:result];
- }
- //测试可以同时识别多个二维码
- }
- }
-
- if (_arrayResult.count < 1)
- {
- bNeedScanResult = YES;
- return;
- }
-
- if (_isNeedCaputureImage)
- {
- [self captureImage];
- }
- else
- {
- [self stopScan];
-
- if (_blockScanResult) {
- _blockScanResult(_arrayResult);
- }
- }
- }
- /**
- @brief 默认支持码的类别
- @return 支持类别 数组
- */
- - (NSArray *)defaultMetaDataObjectTypes
- {
- NSMutableArray *types = [@[AVMetadataObjectTypeQRCode,
- AVMetadataObjectTypeUPCECode,
- AVMetadataObjectTypeCode39Code,
- AVMetadataObjectTypeCode39Mod43Code,
- AVMetadataObjectTypeEAN13Code,
- AVMetadataObjectTypeEAN8Code,
- AVMetadataObjectTypeCode93Code,
- AVMetadataObjectTypeCode128Code,
- AVMetadataObjectTypePDF417Code,
- AVMetadataObjectTypeAztecCode] mutableCopy];
-
- if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_8_0)
- {
- [types addObjectsFromArray:@[
- AVMetadataObjectTypeInterleaved2of5Code,
- AVMetadataObjectTypeITF14Code,
- AVMetadataObjectTypeDataMatrixCode
- ]];
- }
-
- return types;
- }
- #pragma mark --识别条码图片
- + (void)recognizeImage:(UIImage*)image success:(void(^)(NSArray<LBXScanResult*> *array))block;
- {
- if ([[[UIDevice currentDevice]systemVersion]floatValue] < 8.0 )
- {
- if (block) {
- LBXScanResult *result = [[LBXScanResult alloc]init];
- result.strScanned = @"只支持ios8.0之后系统";
- block(@[result]);
- }
- return;
- }
-
- CIDetector*detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }];
- NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];
- NSMutableArray<LBXScanResult*> *mutableArray = [[NSMutableArray alloc]initWithCapacity:1];
- for (int index = 0; index < [features count]; index ++)
- {
- CIQRCodeFeature *feature = [features objectAtIndex:index];
- NSString *scannedResult = feature.messageString;
- NSLog(@"result:%@",scannedResult);
-
- LBXScanResult *item = [[LBXScanResult alloc]init];
- item.strScanned = scannedResult;
- item.strBarCodeType = CIDetectorTypeQRCode;
- item.imgScanned = image;
- [mutableArray addObject:item];
- }
- if (block) {
- block(mutableArray);
- }
- }
- #pragma mark --生成条码
- //下面引用自 https://github.com/yourtion/Demo_CustomQRCode
- #pragma mark - InterpolatedUIImage
- + (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat) size {
- CGRect extent = CGRectIntegral(image.extent);
- CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
- // 创建bitmap;
- size_t width = CGRectGetWidth(extent) * scale;
- size_t height = CGRectGetHeight(extent) * scale;
- CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
- CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
- CGColorSpaceRelease(cs);
- CIContext *context = [CIContext contextWithOptions:nil];
- CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
- CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
- CGContextScaleCTM(bitmapRef, scale, scale);
- CGContextDrawImage(bitmapRef, extent, bitmapImage);
- // 保存bitmap到图片
- CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
- CGContextRelease(bitmapRef);
- CGImageRelease(bitmapImage);
- UIImage *aImage = [UIImage imageWithCGImage:scaledImage];
- CGImageRelease(scaledImage);
- return aImage;
- }
- #pragma mark - QRCodeGenerator
- + (CIImage *)createQRForString:(NSString *)qrString {
- NSData *stringData = [qrString dataUsingEncoding:NSUTF8StringEncoding];
- // 创建filter
- CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
- // 设置内容和纠错级别
- [qrFilter setValue:stringData forKey:@"inputMessage"];
- [qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"];
- // 返回CIImage
- return qrFilter.outputImage;
- }
- #pragma mark - 生成二维码,背景色及二维码颜色设置
- + (UIImage*)createQRWithString:(NSString*)text QRSize:(CGSize)size
- {
- NSData *stringData = [text dataUsingEncoding: NSUTF8StringEncoding];
-
- //生成
- CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
- [qrFilter setValue:stringData forKey:@"inputMessage"];
- [qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"];
-
-
-
-
- CIImage *qrImage = qrFilter.outputImage;
-
- //绘制
- CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:qrImage fromRect:qrImage.extent];
- UIGraphicsBeginImageContext(size);
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGContextSetInterpolationQuality(context, kCGInterpolationNone);
- CGContextScaleCTM(context, 1.0, -1.0);
- CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage);
- UIImage *codeImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- CGImageRelease(cgImage);
-
- return codeImage;
- }
- //引用自:http://www.jianshu.com/p/e8f7a257b612
- + (UIImage*)createQRWithString:(NSString*)text QRSize:(CGSize)size QRColor:(UIColor*)qrColor bkColor:(UIColor*)bkColor
- {
-
- NSData *stringData = [text dataUsingEncoding: NSUTF8StringEncoding];
-
- //生成
- CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
- [qrFilter setValue:stringData forKey:@"inputMessage"];
- [qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"];
-
-
- //上色
- CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor"
- keysAndValues:
- @"inputImage",qrFilter.outputImage,
- @"inputColor0",[CIColor colorWithCGColor:qrColor.CGColor],
- @"inputColor1",[CIColor colorWithCGColor:bkColor.CGColor],
- nil];
-
- CIImage *qrImage = colorFilter.outputImage;
-
- //绘制
- CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:qrImage fromRect:qrImage.extent];
- UIGraphicsBeginImageContext(size);
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGContextSetInterpolationQuality(context, kCGInterpolationNone);
- CGContextScaleCTM(context, 1.0, -1.0);
- CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage);
- UIImage *codeImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- CGImageRelease(cgImage);
-
- return codeImage;
- }
- + (UIImage*)createBarCodeWithString:(NSString*)text QRSize:(CGSize)size
- {
-
- NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:false];
-
- CIFilter *filter = [CIFilter filterWithName:@"CICode128BarcodeGenerator"];
-
- [filter setValue:data forKey:@"inputMessage"];
-
- CIImage *barcodeImage = [filter outputImage];
-
- // 消除模糊
-
- CGFloat scaleX = size.width / barcodeImage.extent.size.width; // extent 返回图片的frame
-
- CGFloat scaleY = size.height / barcodeImage.extent.size.height;
-
- CIImage *transformedImage = [barcodeImage imageByApplyingTransform:CGAffineTransformScale(CGAffineTransformIdentity, scaleX, scaleY)];
-
- return [UIImage imageWithCIImage:transformedImage];
-
- }
- @end
|