日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

IOS7实现扫描二维码

發布時間:2023/12/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IOS7实现扫描二维码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡介: 這里介紹在IOS7 中使用AVFoundation掃描二維碼


?iOS7?以前,在iOS中實現二維碼和條形碼掃描,我們所知的有,兩大開源組件ZBarZXing.?這兩大組件我們都有用過,這里總結下各自的缺點:


ZBar在掃描的靈敏度上,和內存的使用上相對于ZXing上都是較優的,但是對于?“圓角二維碼”?的掃描確很困難。


ZXing??Google Code上的一個開源的條形碼掃描庫,是用java設計的,連Google Glass?都在使用的。但有人為了追求更高效率以及可移植性,出現了c++ port. Github上的Objectivc-C port,其實就是用OC代碼封裝了一下而已,而且已經停止維護。這樣效率非常低,在instrument下面可以看到CPU和內存瘋漲,在內存小的機器上很容易崩潰。


iOS 7以后AVFoundation開始支持掃描了.AVFoundation無論在掃描靈敏度和性能上來說都是最優的,所以毫無疑問我們應該切換到AVFoundation,需要兼容iOS 6或之前的版本可以用zbarzxing代替。


下面介紹本文的重點,無論你是用以上哪一種或其他的解決方案,都需要知道下面兩點。


1. 圖片很小的二維碼

以前測試提了一個bug,說有二維碼掃不了,拿到二維碼一看,是個很小的二維碼,邊長不到1cm,于是就修改了 sessionPreset1080p 的,當時用的是ZXing, 當把圖片質量改清楚時,也造成了性能的下降,基本打開掃描界面就會報memoryWarning,但是也確實解決了小二維碼掃描的問題。

AVCaptureSession 可以設置 sessionPreset 屬性,這個決定了視頻輸入每一幀圖像質量的大小。

  • AVCaptureSessionPreset320x240
  • AVCaptureSessionPreset352x288
  • AVCaptureSessionPreset640x480
  • AVCaptureSessionPreset960x540
  • AVCaptureSessionPreset1280x720
  • AVCaptureSessionPreset1920x1080

以上列舉了部分的屬性值,分別代表輸入圖片質量大小,一般來說AVCaptureSessionPreset640x480就夠使用,但是如果要保證較小的二維碼圖片能快速掃描,最好設置高些,如AVCaptureSessionPreset1920x1080(就是我們常說的1080p).


2. scanCrop

另一個提升掃描速度和性能的就是設置解析的范圍,在zbarzxing中就是scanCrop, AVFoundation中設置 AVCaptureMetadataOutput rectOfInterest 屬性來配置解析范圍。

最開始我按照文檔說的按照比例值來設置這個屬性,如下:

CGSize size = self.view.bounds.size; CGRect cropRect = CGRectMake(40, 100, 240, 240); captureOutput.rectOfInterest = CGRectMake(cropRect.origin.x/size.width,cropRect.origin.y/size.height,cropRect.size.width/size.width,cropRect.size.height/size.height);


但是發現,
Ops, 好像不對啊,掃不到了,明顯不正確呢,于是猜想: AVCapture輸出的圖片大小都是橫著的,而iPhone的屏幕是豎著的,那么我把它旋轉90°呢:

CGSize size = self.view.bounds.size; CGRect cropRect = CGRectMake(40, 100, 240, 240); captureOutput.rectOfInterest = CGRectMake(cropRect.origin.y/size.height,cropRect.origin.x/size.width,cropRect.size.height/size.height,cropRect.size.width/size.width);

OK,貌似對了,在iPhone5上一切工作良好,但是在4s上,或者換了sessionPreset的大小之后,這個框貌似就不那么準確了, 可能發現超出框上下一些也是可以掃描出來的。 再次猜想: 圖片的長寬比和手機屏幕不是一樣的,這個rectOfInterest是相對于圖片大小的比例。比如iPhone4s屏幕大小是 640x960, 而圖片輸出大小是 1920x1080.?


iPhone4s屏幕,大小640x960, 上面代表AVCaptureVideoPreviewLayer中預覽到的圖片位置,在圖片輸入為1920x1080大小時,實際大小上下會被截取一點的,因為我們AVCaptureVideoPreviewLayer設置的videoGravityAVLayerVideoGravityResizeAspectFill, 類似于UIViewUIViewContentModeScaleAspectFill效果。


于是我對大小做了一下修正:
















CGSize?size?=?self.view.bounds.size;

CGRect?cropRect?=?CGRectMake(40,?100,?240,?240);

CGFloat?p1?=?size.height/size.width;

CGFloat?p2?=?1920./1080.;??//使用了1080p的圖像輸出

if?(p1?<?p2)?{

??CGFloat?fixHeight?=?bounds.size.width?*?1920.?/?1080.;

??CGFloat?fixPadding?=?(fixHeight?-?size.height)/2;

??captureOutput.rectOfInterest?=?CGRectMake((cropRect.origin.y?+?fixPadding)/fixHeight,

??????????????????????????????????????????????cropRect.origin.x/size.width,

??????????????????????????????????????????????cropRect.size.height/fixHeight,

??????????????????????????????????????????????cropRect.size.width/size.width);

}?else?{

????CGFloat?fixWidth?=?bounds.size.height?*?1080.?/?1920.;

????CGFloat?fixPadding?=?(fixWidth?-?size.width)/2;

????captureOutput.rectOfInterest?=?CGRectMake(cropRect.origin.y/size.height,

??????????????????????????????????????????????(cropRect.origin.x?+?fixPadding)/fixWidth,

??????????????????????????????????????????????cropRect.size.height/size.height,

??????????????????????????????????????????????cropRect.size.width/fixWidth);

}

經過上面的驗證,證實了猜想rectOfInterest是基于圖像的大小裁剪的。


下面跟上本人時間用AVFoundation掃描的測試代碼,沒有做UI調整只能單次掃描:


#import

@interface ViewController : UIViewController


@property (strong,nonatomic)AVCaptureDevice *device;

@property (strong,nonatomic)AVCaptureDeviceInput *input;

@property (strong,nonatomic)AVCaptureMetadataOutput *output;

@property (strong,nonatomic)AVCaptureSession *session;

@property (strong,nonatomic)AVCaptureVideoPreviewLayer *preview;



@end


- (IBAction)setupCamera

{

? ? // Device

? ? self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

?? ?

? ? // Input

? ? self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];

?? ?

? ? // Output

? ? self.output = [[AVCaptureMetadataOutput alloc]init];

? ? [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

?? ?

? ? // Session

? ? self.session = [[AVCaptureSession alloc]init];

? ? [self.session setSessionPreset:AVCaptureSessionPresetHigh];

? ? if ([self.session canAddInput:self.input])

? ? {

? ? ? ? [self.session addInput:self.input];

? ? }

? ? if ([self.session canAddOutput:self.output])

? ? {

? ? ? ? [self.session addOutput:self.output];

? ? }

?? ?

? ? // 條碼類型

? ? self.output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode];

?? ?

? ? // Preview

? ? self.preview = [AVCaptureVideoPreviewLayer layerWithSession:self.session];

? ? self.preview.videoGravity =AVLayerVideoGravityResizeAspectFill;

? ? self.preview.frame =CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height);

? ? [self.view.layer addSublayer:self.preview];

?? ?

? ? // Start

? ? [self.session startRunning];

}

//

//條碼類型有如下幾種:

//AVMetadataObjectTypeUPCECode

//AVMetadataObjectTypeCode39Code

//AVMetadataObjectTypeCode39Mod43Code

//AVMetadataObjectTypeEAN13Code

//AVMetadataObjectTypeEAN8Code

//AVMetadataObjectTypeCode93Code

//AVMetadataObjectTypeCode128Code

//AVMetadataObjectTypePDF417Code

//AVMetadataObjectTypeQRCode

//AVMetadataObjectTypeAztecCode

//

//掃瞄到二維碼之后,會調用delegate


#pragma mark AVCaptureMetadataOutputObjectsDelegate

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection

{

? ? NSString *stringValue;

?? ?

? ? if ([metadataObjects count] >0) {

? ? ? ? AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];

? ? ? ? stringValue = metadataObject.stringValue;

? ? ? ? NSLog(@"==========%@",stringValue);

? ? }

?? ?

? ? [_session stopRunning];

?? ?

? ? UIAlertView *alert = [[UIAlertView alloc]initWithTitle:nil

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? message:stringValue

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? delegate:nil

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cancelButtonTitle:@"OK"

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? otherButtonTitles:nil,nil];

? ? [alert show];

?

}

總結

以上是生活随笔為你收集整理的IOS7实现扫描二维码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。