原文链接:http://blog.youkuaiyun.com/whjblog/article/details/15809859
iOS二维码扫描开源库主要有Zbar和ZXing,在完成项目的过程中都用过,开始时用了Zbar,但其相对于ZXing扫描识别效率太低,无法达到项目要求,所以改用ZXing。两个开源库都可以识别二维码,但ZBar还支持条形码,ZXing识别条形码还需要改一些地方。
一、ZBar的使用
1.下载ZBar SDK,将ZBarSDK拖动到Xcode项目
下载地址:https://github.com/bmorton/ZBarSDK
2.添加framework框架
* AVFoundation.framework (weak) * CoreMedia.framework (weak) * CoreVideo.framework (weak) * QuartzCore.framework
3.扫描代码
引入头文件 #import "ZBarSDK.h" ,实现ZBarReaderDelegate协议
- ZBarReaderViewController *reader = [ZBarReaderViewController new];
- reader.readerDelegate = self;
- reader.supportedOrientationsMask = ZBarOrientationMaskAll;
- ZBarImageScanner *scanner = reader.scanner;
- [scanner setSymbology: ZBAR_I25
- config: ZBAR_CFG_ENABLE
- to: 0];
- [self presentModalViewController:reader animated:YES];
- [reader release];
扫描结果回调
- - (void) imagePickerController: (UIImagePickerController*) reader didFinishPickingMediaWithInfo: (NSDictionary*) info
- {
- id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults];
- ZBarSymbol *symbol = nil;
- for(symbol in results)
- break;
- text = symbol.data ;
- }
还可以在ZBarReaderViewController自定义扫描界面和扫描区域(scanCrop)。
二、ZXing的使用
1.下载ZXIng,下载地址: https://github.com/zxing/zxing .由于支持各种语言,整个工程比较大,IOS 只需保留cpp和iphone这2个文件夹,整个目录结构不变,cpp文件夹只保留cpp/core/src/zxing下面的内容,其余都可以全部删除。然后把删减好的zxing目录移动到我们的iOS项目的目录下(也可以右击选择Add files to ‘project’),并在 zxing/iphone/ZXingWidget/
目录下把ZXingWidget.xcodeproj
拖动到我们的项目工程中。
2.选择 target ——>Build Phases 在 Link Binary with Libraries里 添加libZXingWidget.a,在Target Dependencies添加
ZXingWidget
。在target ——>Build Settings ——>Headers Search Path 添加两个路径:
.
/zxing/iphone/ZXingWidget/Classes
./zxing/cpp/core/src
第一个设成recursive ,第二个设成non-recursive
添加一下frameworks 支持
- AVFoundation
- AudioToolbox
- CoreVideo
- CoreMedia
- libiconv
- AddressBook
- AddressBookUI
3.扫描代码
(1)直接引用
头文件:
#import <ZXingWidgetController.h>
#import <QRCodeReader.h>
扫描调用代码:
- ZXingWidgetController *widController = [[ZXingWidgetController alloc] initWithDelegate:self showCancel:YES OneDMode:NO];
- NSMutableSet *readers = [[NSMutableSet alloc] init];
- QRCodeReader *qrcodeReader = [[QRCodeReader alloc] init];
- [readers addObject:qrcodeReader];
- widController.readers = readers;
- [self presentViewController:widController animated:YES completion:^{}];
扫描结果回调:
- @protocol ZXingDelegate
- - (void)zxingController:(ZXingWidgetController*)controller didScanResult:(NSString *)result;
- - (void)zxingControllerDidCancel:(ZXingWidgetController*)controller;
- @end
还需要把引入的.m文件改为.mm。
(2)自定义扫描
我的项目要求中需要自定义扫描界面和扫描区域,还要加入C语言混编,所以就用了这种方法。
头文件:
- #import <AssetsLibrary/AssetsLibrary.h>
- #import <QRCodeReader.h>
- #import <TwoDDecoderResult.h>
- #import <Decoder.h>
初始化AVCapture
- - (void)initCapture
- {
- AVCaptureDevice* inputDevice =
- [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
- AVCaptureDeviceInput *captureInput =
- [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:nil];
- AVCaptureVideoDataOutput *captureOutput = [[AVCaptureVideoDataOutput alloc] init];
- captureOutput.alwaysDiscardsLateVideoFrames = YES;
- [captureOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
- NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
- NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
- NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
- [captureOutput setVideoSettings:videoSettings];
- self.captureSession = [[[AVCaptureSession alloc] init] autorelease];
- NSString* preset = 0;
- if (NSClassFromString(@"NSOrderedSet") && // Proxy for "is this iOS 5" ...
- [UIScreen mainScreen].scale > 1 &&
- isIPad() &&
- [inputDevice
- supportsAVCaptureSessionPreset:AVCaptureSessionPresetiFrame960x540]) {
- preset = AVCaptureSessionPresetiFrame960x540;
- }
- if (!preset) {
- preset = AVCaptureSessionPresetMedium;
- }
- self.captureSession.sessionPreset = preset;
- [self.captureSession addInput:captureInput];
- [self.captureSession addOutput:captureOutput];
- [captureOutput release];
- if (!self.prevLayer) {
- self.prevLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
- }
- self.prevLayer.frame = self.view.bounds;
- self.prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
- [self.view.layer addSublayer: self.prevLayer];
- [self.captureSession startRunning];
- }
得到AVCapture回调函数
- - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
- {
- if (!isScanning||delegate==nil) {
- return;
- }
- if (sampleBuffer)
- {
- //将sampleBuffer转化为UIImage
- UIImage *image = [self imageFromSampleBuffer:sampleBuffer];
- //用Decoder来解析识别图像
- [self decodeImage:image];
- }
- }
- - (void)decodeImage:(UIImage *)image
- {
- NSMutableSet *qrReader = [[NSMutableSet alloc] init];
- QRCodeReader *qrcoderReader = [[QRCodeReader alloc] init];
- [qrReader addObject:qrcoderReader];
- [qrcoderReader release];
- Decoder *decoder = [[Decoder alloc] init];
- decoder.delegate = self;
- decoder.readers = qrReader;
- [decoder decodeImage:image];
- [decoder release];
- [qrReader release];
- }
- @optional
- - (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset;
- - (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset withResult:(TwoDDecoderResult *)result;
- - (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset reason:(NSString *)reason;
- - (void)decoder:(Decoder *)decoder foundPossibleResultPoint:(CGPoint)point;
注意扫描的画面不会跟着设备旋转,当横竖转换是需要改变画面
- CGFloat angle = 0.0f;
- switch (barOrientation)
- {
- case UIInterfaceOrientationPortrait:
- angle = 0.0f;
- break;
- case UIInterfaceOrientationPortraitUpsideDown:
- angle = M_PI;
- break;
- case UIInterfaceOrientationLandscapeLeft:
- angle = M_PI / 2;
- break;
- case UIInterfaceOrientationLandscapeRight:
- angle = -M_PI / 2;
- break;
- default:
- break;
- }
- CATransform3D transform = CATransform3DMakeRotation(angle, 0, 0, 1.0);
- self.captureVideoPreviewLayer.transform =transform;
- self.captureVideoPreviewLayer.frame = layerframe;