cocos2dx-lua在ios上實現生成及掃描二維碼

Kaitiren發表於2017-09-26


首先說明下,我是支援用iOS原生方法實現的。不過掃描二維碼原生方法不支援ios7.0之前的裝置,所以生成二維碼用的原生方法實現,而掃描二維碼用zBar sdk實現的(當然也可以用google官方的zXing sdk)。其中zBar中包含生成二維碼的方法,而且更多樣,我只是喜歡儘量用原生方法來實現。

這裡我把所有生成二維碼的程式碼和lua呼叫的掃描二維碼方法都放在了專案->frameworks->runtime-src->proj.ios_mac->ios->AppController.h和AppController.mm中

zBar sdk及相關類放到了 專案->frameworks->runtime-src->proj.ios_mac->ios下。

-----1.原生生成二維碼

------------1.1AppController.h中新增程式碼:

  1. //生成二維碼  
  2. +(CIImage *) creatQRcodeWithUrlstring:(NSString *)urlString;  
  3. //改變圖片大小 (正方形圖片)  
  4. + (UIImage *)changeImageSizeWithCIImage:(CIImage *)ciImage andSize:(CGFloat)size;  
  5. //儲存(暫時沒用)  
  6. +(BOOL)writeImage:(UIImage*)image toFileAtPath:(NSString*)aPath;  
  7. //生成二維碼  
  8. +(void)createQRCode:(NSDictionary *)info;  

------------1.2AppController.mm中新增程式碼:

  1. /** 
  2.  *  根據字串生成二維碼 CIImage 物件 
  3.  * 
  4.  *  @param urlString 需要生成二維碼的字串 
  5.  * 
  6.  *  @return 生成的二維碼 
  7.  */  
  8. + (CIImage *)creatQRcodeWithUrlstring:(NSString *)urlString{  
  9.     // 1.例項化二維碼濾鏡  
  10.     CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];  
  11.     // 2.恢復濾鏡的預設屬性 (因為濾鏡有可能儲存上一次的屬性)  
  12.     [filter setDefaults];  
  13.     // 3.將字串轉換成NSdata  
  14.     NSData *data  = [urlString dataUsingEncoding:NSUTF8StringEncoding];  
  15.     // 4.通過KVO設定濾鏡, 傳入data, 將來濾鏡就知道要通過傳入的資料生成二維碼  
  16.     [filter setValue:data forKey:@"inputMessage"];  
  17.     // 5.生成二維碼  
  18.     CIImage *outputImage = [filter outputImage];  
  19.     return outputImage;  
  20. }  
  21.   
  22. /** 
  23.  *  改變圖片大小 (正方形圖片) 
  24.  * 
  25.  *  @param ciImage 需要改變大小的CIImage 物件的圖片 
  26.  *  @param size    圖片大小 (正方形圖片 只需要一個數) 
  27.  * 
  28.  *  @return 生成的目標圖片 
  29.  */  
  30. + (UIImage *)changeImageSizeWithCIImage:(CIImage *)ciImage andSize:(CGFloat)size{  
  31.     CGRect extent = CGRectIntegral(ciImage.extent);  
  32.     CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));  
  33.       
  34.     // 建立bitmap;  
  35.     size_t width = CGRectGetWidth(extent) * scale;  
  36.     size_t height = CGRectGetHeight(extent) * scale;  
  37.     CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();  
  38.     CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);  
  39.     CIContext *context = [CIContext contextWithOptions:nil];  
  40.     CGImageRef bitmapImage = [context createCGImage:ciImage fromRect:extent];  
  41.     CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);  
  42.     CGContextScaleCTM(bitmapRef, scale, scale);  
  43.     CGContextDrawImage(bitmapRef, extent, bitmapImage);  
  44.       
  45.     // 儲存bitmap到圖片  
  46.     CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);  
  47.     CGContextRelease(bitmapRef);  
  48.     CGImageRelease(bitmapImage);  
  49.       
  50.     return [UIImage imageWithCGImage:scaledImage];  
  51. }  
  52.   
  53. + (BOOL)writeImage:(UIImage*)image toFileAtPath:(NSString*)aPath  
  54. {  
  55.     if ((image == nil) || (aPath == nil) || ([aPath isEqualToString:@""]))  
  56.         return NO;  
  57.     @try  
  58.     {  
  59.         NSData *imageData = nil;  
  60.         NSString *ext = [aPath pathExtension];  
  61.         if ([ext isEqualToString:@"png"])  
  62.         {  
  63.             imageData = UIImagePNGRepresentation(image);  
  64.         }  
  65.         else  
  66.         {  
  67.             // the rest, we write to jpeg  
  68.             // 0. best, 1. lost. about compress.  
  69.             imageData = UIImageJPEGRepresentation(image, 0);  
  70.         }  
  71.         if ((imageData == nil) || ([imageData length] <= 0))  
  72.             return NO;  
  73.         [imageData writeToFile:aPath atomically:YES];  
  74.         return YES;  
  75.     }  
  76.     @catch (NSException *e)  
  77.     {  
  78.         NSLog(@"create thumbnail exception.");  
  79.     }  
  80.     return NO;  
  81. }  
  82.   
  83. /* 
  84.  * 專案-TARGETS-fightGame-mobile-Build Phases-Link Binary With Libraries新增CoreImage.framework 
  85.  */  
  86. +(void) createQRCode:(NSDictionary *)info  
  87. {  
  88.     int _callBack = [[info objectForKey:@"listener"] intValue];  
  89.     NSString *qrCodeStr = [info objectForKey:@"qrCodeStr"];  
  90.       
  91.     CIImage *ciImage = [self creatQRcodeWithUrlstring:qrCodeStr];  
  92.     UIImage *uiImage = [self changeImageSizeWithCIImage:ciImage andSize:180];  
  93.     NSData *imageData = UIImagePNGRepresentation(uiImage);  
  94.       
  95.     std::string path = cocos2d::FileUtils::getInstance()->getWritablePath() + "qrCode.png";  
  96.     const char* pathC = path.c_str();  
  97.     NSString * pathN = [NSString stringWithUTF8String:pathC];  
  98.     bool isSuccess = [imageData writeToFile:pathN atomically:YES];  
  99.       
  100.     cocos2d::LuaBridge::pushLuaFunctionById(_callBack);  
  101.     cocos2d::LuaValueDict dict;  
  102.     dict["isSuccess"] =cocos2d::LuaValue::booleanValue(isSuccess);  
  103.     cocos2d::LuaBridge::getStack()->pushLuaValueDict( dict );  
  104.     cocos2d::LuaBridge::getStack()->executeFunction(1);  
  105.     cocos2d::LuaBridge::releaseLuaFunctionById(_callBack);  
  106. }  

其中createQRcode方法為最終lua掉用oc的方法,將生成的圖片存到cocos2dx的writablePath下,並儲存為"qrCode.png"。最後在lua端取出用sprite顯示

------------1.3lua呼叫createQRcode方法,並顯示

  1. local callBack = function (message)  
  2.     local filePath = cc.FileUtils:getInstance():getWritablePath()  
  3.     filePath = filePath.."qrCode.png"  
  4.   
  5.     local rect = cc.rect(0, 0, 180, 180)  
  6.     local sprite = cc.Sprite:create()   
  7.     sprite:initWithFile(filePath, rect)  
  8.     sprite:setPosition(300, 300)  
  9.     self:addChild(sprite)  
  10. end  
  11. local info = {listener = callBack, qrCodeStr = "https://www.baidu.com/"}  
  12. luaoc.callStaticMethod("AppController""createQRCode", info)  

------------1.4新增CoreImage.framework依賴框架(二維碼掃描需要用到)

專案->TARGETS->Build Phases->Link Binary With Libraries->左下角“+”號,search框中輸入CoreImage.framework,選擇匹配的選項即可。
-----2.zBar sdk實現二維碼掃描

------------2.1下載zBar sdk 
地址在後面給出。

------------2.2將zBarSDK解壓並將解壓後的zBarSDK匯入到工程專案->frameworks->runtime-src->proj.ios_mac->ios下。

解壓後的zBarSDK目錄包含:Headers,libzbar.a,Resources。

如果匯入工程後沒有自動新增libzbar.a依賴框架,則需要手動新增該依賴框架(如1.4)。

------------2.3專案->frameworks->runtime-src->proj.ios_mac->ios->zBarSDK下新建ZCZBarViewController.h和ZCZBarViewController.mm兩個檔案,並匯入工程,程式碼如下。
------------2.4ZCZBarViewController.h程式碼:

  1. /* 
  2.  版本說明 iOS研究院 305044955 
  3.  1.8版本 剔除生成二維碼檔案,使用iOS7原生生成二維碼 
  4.  1.7版本 修復了開啟相機點選,使用者如果點選拒絕,會導致崩潰的問題 
  5.  1.6版本 增加了支援了區別條碼和二維碼,可以關閉掃描二維碼來增加條碼掃描速度 
  6.  1.5版本 修正了iOS6下掃描會卡死,增加了iOS7下支援條形碼,修改了演算法,增加了效率 
  7.  1.4版本 支援iOS8系統,修改了相應UI的適配問題 
  8.  1.3版本 全新支援arm7s arm64 全新支援ARC 
  9.  1.2版本 ZC封裝的ZBar二維碼SDK 
  10.     1、更新類名從CustomViewController更改為ZCZBarViewController 
  11.     2、刪除掉代理的相關程式碼 
  12.  1.1版本 ZC封裝的ZBar二維碼SDK~ 
  13.     1、增加block回撥 
  14.     2、取消代理 
  15.     3、增加適配IOS7(ios7在AVFoundation中增加了掃描二維碼功能) 
  16.  1.0版本 ZC封裝的ZBar二維碼SDK~1.0版本初始建立 
  17.   
  18.  二維碼編譯順序 
  19.  Zbar編譯 
  20.  需要新增AVFoundation  CoreMedia  CoreVideo QuartzCore libiconv 
  21.   
  22.   
  23. //示例程式碼 
  24. 掃描程式碼 
  25. BOOL代表是否關閉二維碼掃描,專門掃描條形碼 
  26.  ZCZBarViewController*vc=[[ZCZBarViewController alloc]initWithIsQRCode:NO Block:^(NSString *result, BOOL isFinish) { 
  27.  if (isFinish) { 
  28.  NSLog(@"最後的結果%@",result); 
  29.  } 
  30.   
  31.  }]; 
  32.   
  33.  [self presentViewController:vc animated:YES completion:nil]; 
  34.   
  35.   
  36. 生成二維碼 
  37.  [ZCZBarViewController createImageWithImageView:imageView String:@"http://www.baidu.com"Scale:4]; 
  38.  */  
  39. #import <UIKit/UIKit.h>  
  40. #import <AVFoundation/AVFoundation.h>  
  41. #import "ZBarReaderController.h"  
  42. #import <CoreImage/CoreImage.h>  
  43. #define IOS7 [[[UIDevice currentDevice] systemVersion]floatValue]>=7  
  44.   
  45.   
  46. @interface ZCZBarViewController : UIViewController<AVCaptureVideoDataOutputSampleBufferDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate,ZBarReaderDelegate,AVCaptureMetadataOutputObjectsDelegate>  
  47. {  
  48.     int num;  
  49.     BOOL upOrdown;  
  50.     NSTimer * timer;  
  51.     UIImageView*_line;  
  52. }  
  53.   
  54.   
  55. @property (nonatomic,strong) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;  
  56. @property (nonatomic, strong) AVCaptureSession *captureSession;  
  57.   
  58. @property (nonatomic, assign) BOOL isScanning;  
  59.   
  60. @property (nonatomic,copy)void(^ScanResult)(NSString*result,BOOL isSucceed);  
  61. @property (nonatomic)BOOL isQRCode;  
  62.   
  63.   
  64. //初始化函式  
  65. -(id)initWithIsQRCode:(BOOL)isQRCode Block:(void(^)(NSString*,BOOL))a;  
  66.   
  67. //正規表示式對掃描結果篩選  
  68. +(NSString*)zhengze:(NSString*)str;  
  69.   
  70. //建立二維碼  
  71. +(void)createImageWithImageView:(UIImageView*)imageView String:(NSString*)str Scale:(CGFloat)scale;  
  72.   
  73.   
  74. @end  

------------2.4ZCZBarViewController.mm程式碼:

  1. #import "ZCZBarViewController.h"  
  2. #import <AssetsLibrary/AssetsLibrary.h>  
  3. @interface ZCZBarViewController ()  
  4.   
  5. @end  
  6.   
  7. #define WIDTH ( ([UIScreen mainScreen].bounds.size.width>[UIScreen mainScreen].bounds.size.height)?[UIScreen mainScreen].bounds.size.width:[UIScreen mainScreen].bounds.size.height )  
  8. //[UIScreen mainScreen].bounds.size.width  
  9. #define HEIGHT ( ([UIScreen mainScreen].bounds.size.width<[UIScreen mainScreen].bounds.size.height)?[UIScreen mainScreen].bounds.size.width:[UIScreen mainScreen].bounds.size.height )  
  10. //[UIScreen mainScreen].bounds.size.height  
  11.   
  12.   
  13. @implementation ZCZBarViewController  
  14.   
  15. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil  
  16. {  
  17.     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];  
  18.     if (self) {  
  19.         // Custom initialization  
  20.     }  
  21.     return self;  
  22. }  
  23. -(id)initWithIsQRCode:(BOOL)isQRCode Block:(void(^)(NSString*,BOOL))a  
  24. {  
  25.     if (self=[super init]) {  
  26.         self.ScanResult=a;  
  27.         self.isQRCode=isQRCode;  
  28.           
  29.     }  
  30.       
  31.     return self;  
  32. }  
  33.   
  34.   
  35. -(void)createView{  
  36.       
  37. //qrcode_scan_bg_Green_iphone5@2x.png  qrcode_scan_bg_Green@2x.png  
  38.     UIImage*image= [UIImage imageNamed:@"qrcode_scan_bg_Green@2x.png"];  
  39.     float capWidth=image.size.width/2;  
  40.     float capHeight=image.size.height/2;  
  41.       
  42.     image=[image stretchableImageWithLeftCapWidth:capWidth topCapHeight:capHeight];  
  43.     UIImageView* bgImageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, 64, WIDTH, HEIGHT-64)];  
  44.     //bgImageView.contentMode=UIViewContentModeTop;  
  45.     bgImageView.clipsToBounds=YES;  
  46.     bgImageView.image=image;  
  47.     bgImageView.userInteractionEnabled=YES;  
  48.     [self.view addSubview:bgImageView];  
  49.       
  50. //    UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(0, bgImageView.frame.size.height-140, WIDTH, 40)];  
  51. //    label.text = @"將取景框對準二維碼,即可自動掃描。";  
  52. //    label.textColor = [UIColor whiteColor];  
  53. //    label.textAlignment = NSTextAlignmentCenter;  
  54. //    label.lineBreakMode = NSLineBreakByWordWrapping;  
  55. //    label.numberOfLines = 2;  
  56. //    label.font=[UIFont systemFontOfSize:12];  
  57. //    label.backgroundColor = [UIColor clearColor];  
  58. //    [bgImageView addSubview:label];  
  59.       
  60.   
  61.       
  62.       
  63.     _line = [[UIImageView alloc] initWithFrame:CGRectMake((WIDTH-220)/2, 70, 220, 2)];  
  64.     _line.image = [UIImage imageNamed:@"qrcode_scan_light_green.png"];  
  65.     [bgImageView addSubview:_line];  
  66.      
  67.       
  68. //  //下方相簿  
  69. //    UIImageView*scanImageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, HEIGHT-100, WIDTH, 100)];  
  70. //    scanImageView.image=[UIImage imageNamed:@"qrcode_scan_bar.png"];  
  71. //    scanImageView.userInteractionEnabled=YES;  
  72. //    [self.view addSubview:scanImageView];  
  73. //    NSArray*unSelectImageNames=@[@"qrcode_scan_btn_photo_nor.png",@"qrcode_scan_btn_flash_nor.png",@"qrcode_scan_btn_myqrcode_nor.png"];  
  74. //    NSArray*selectImageNames=@[@"qrcode_scan_btn_photo_down.png",@"qrcode_scan_btn_flash_down.png",@"qrcode_scan_btn_myqrcode_down.png"];  
  75. //      
  76. //    for (int i=0; i<unSelectImageNames.count; i++) {  
  77. //        UIButton*button=[UIButton buttonWithType:UIButtonTypeCustom];  
  78. //        [button setImage:[UIImage imageNamed:unSelectImageNames[i]] forState:UIControlStateNormal];  
  79. //        [button setImage:[UIImage imageNamed:selectImageNames[i]] forState:UIControlStateHighlighted];  
  80. //        button.frame=CGRectMake(WIDTH/3*i, 0, WIDTH/3, 100);  
  81. //        [scanImageView addSubview:button];  
  82. //        if (i==0) {  
  83. //            [button addTarget:self action:@selector(pressPhotoLibraryButton:) forControlEvents:UIControlEventTouchUpInside];  
  84. //        }  
  85. //        if (i==1) {  
  86. //            [button addTarget:self action:@selector(flashLightClick) forControlEvents:UIControlEventTouchUpInside];  
  87. //        }  
  88. //        if (i==2) {  
  89. //            button.hidden=YES;  
  90. //        }  
  91. //          
  92. //    }  
  93.       
  94.       
  95.     //假導航  
  96. //    UIImageView*navImageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, 64)];  
  97. //    navImageView.image=[UIImage imageNamed:@"qrcode_scan_bar.png"];  
  98. //    navImageView.userInteractionEnabled=YES;  
  99. //    [self.view addSubview:navImageView];  
  100.       
  101.     UILabel*titleLabel=[[UILabel alloc]initWithFrame:CGRectMake(WIDTH/2-32, 20, 64, 44)];  
  102.     titleLabel.textColor=[UIColor whiteColor];  
  103.     titleLabel.backgroundColor = [UIColor clearColor];  
  104.     titleLabel.text=@"掃一掃";  
  105.     [self.view addSubview:titleLabel];  
  106. //    [navImageView addSubview:titleLabel];  
  107.       
  108.     
  109.       
  110.     UIButton*button = [UIButton buttonWithType:UIButtonTypeCustom];  
  111.     [button setImage:[UIImage imageNamed:@"qrcode_scan_titlebar_back_pressed@2x.png"] forState:UIControlStateHighlighted];  
  112.     [button setImage:[UIImage imageNamed:@"qrcode_scan_titlebar_back_nor.png"] forState:UIControlStateNormal];  
  113.   
  114.       
  115.     [button setFrame:CGRectMake(10,10, 48, 48)];  
  116.     [button addTarget:self action:@selector(pressCancelButton:) forControlEvents:UIControlEventTouchUpInside];  
  117.     [self.view addSubview:button];  
  118.   
  119.    timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(animation1) userInfo:nil repeats:YES];  
  120. }  
  121.   
  122. -(void)animation1  
  123. {  
  124.   
  125.     [UIView animateWithDuration:2 animations:^{  
  126.           
  127.          _line.frame = CGRectMake((WIDTH-220)/2, 70+HEIGHT-310, 220, 2);  
  128.     }completion:^(BOOL finished) {  
  129.         [UIView animateWithDuration:2 animations:^{  
  130.           _line.frame = CGRectMake((WIDTH-220)/2, 70, 220, 2);  
  131.         }];  
  132.       
  133.     }];  
  134.       
  135. }  
  136. //開啟關閉閃光燈  
  137. -(void)flashLightClick{  
  138.     AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];  
  139.       
  140.     if (device.torchMode==AVCaptureTorchModeOff) {  
  141.         //閃光燈開啟  
  142.         [device lockForConfiguration:nil];  
  143.         [device setTorchMode:AVCaptureTorchModeOn];  
  144.           
  145.     }else {  
  146.         //閃光燈關閉  
  147.           
  148.         [device setTorchMode:AVCaptureTorchModeOff];  
  149.     }  
  150.   
  151. }  
  152.   
  153. - (void)viewDidLoad  
  154. {  
  155.     
  156.     //相機介面的定製在self.view上載入即可  
  157.     BOOL Custom= [UIImagePickerController  
  158.                   isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];//判斷攝像頭是否能用  
  159.     if (Custom) {  
  160.         [self initCapture];//啟動攝像頭  
  161.     }else{  
  162.         self.view.backgroundColor=[UIColor whiteColor];  
  163.     }  
  164.     [super viewDidLoad];  
  165.     [self createView];  
  166.   
  167.       
  168.       
  169. }  
  170. #pragma mark 選擇相簿  
  171. - (void)pressPhotoLibraryButton:(UIButton *)button  
  172. {  if (timer) {  
  173.     [timer invalidate];  
  174.     timer=nil;  
  175. }  
  176.     _line.frame = CGRectMake((WIDTH-220)/2, 70, 220, 2);  
  177.     num = 0;  
  178.     upOrdown = NO;  
  179.       
  180.       
  181.     UIImagePickerController *picker = [[UIImagePickerController alloc] init];  
  182.     picker.allowsEditing = YES;  
  183.     picker.delegate = self;  
  184.     picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;  
  185.     [self presentViewController:picker animated:YES completion:^{  
  186.         self.isScanning = NO;  
  187.         [self.captureSession stopRunning];  
  188.     }];  
  189. }  
  190. #pragma mark 點選取消  
  191. - (void)pressCancelButton:(UIButton *)button  
  192. {  
  193.     self.isScanning = NO;  
  194.     [self.captureSession stopRunning];  
  195.       
  196.     self.ScanResult(nil,NO);  
  197.     if (timer) {  
  198.         [timer invalidate];  
  199.         timer=nil;  
  200.     }  
  201.     _line.frame = CGRectMake((WIDTH-220)/2, 70, 220, 2);  
  202.     num = 0;  
  203.     upOrdown = NO;  
  204.     [self dismissViewControllerAnimated:YES completion:nil];  
  205. }  
  206. #pragma mark 開啟相機  
  207. - (void)initCapture  
  208. {  
  209.     //ios6上也沒有“設定--隱私--相機” 那一項  
  210.     if (IOS7) {  
  211.         NSString *mediaType = AVMediaTypeVideo;  
  212.         AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];  
  213.           
  214.         if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied){  
  215.             NSString*str=[NSString stringWithFormat:@"請在系統設定-%@-相機中開啟允許使用相機",  [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey]];  
  216.             UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"提示" message:str delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];  
  217.             [alert show];  
  218.             return;  
  219.         }  
  220.     }  
  221.       
  222.     self.captureSession = [[AVCaptureSession alloc] init];  
  223.       
  224.     AVCaptureDevice* inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];  
  225.       
  226.     AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:nil];  
  227.     [self.captureSession addInput:captureInput];  
  228.       
  229.     AVCaptureVideoDataOutput *captureOutput = [[AVCaptureVideoDataOutput alloc] init];  
  230.     captureOutput.alwaysDiscardsLateVideoFrames = YES;  
  231.       
  232.       
  233.     if (IOS7) {  
  234.         AVCaptureMetadataOutput*_output=[[AVCaptureMetadataOutput alloc]init];  
  235.         [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];  
  236.         [self.captureSession setSessionPreset:AVCaptureSessionPresetHigh];  
  237.         [self.captureSession addOutput:_output];  
  238.         //在這裡修改了,可以讓原生相容二維碼和條形碼,無需在使用Zbar  
  239.           
  240.         if (_isQRCode) {  
  241.             _output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode];  
  242.   
  243.              
  244.         }else{  
  245.              _output.metadataObjectTypes =@[AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code,AVMetadataObjectTypeCode128Code,AVMetadataObjectTypeQRCode];  
  246.         }  
  247.          
  248.           
  249.         if (!self.captureVideoPreviewLayer) {  
  250.             self.captureVideoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];  
  251.         }  
  252.         // NSLog(@"prev %p %@", self.prevLayer, self.prevLayer);  
  253.         self.captureVideoPreviewLayer.frame = CGRectMake(0, 0, WIDTH, HEIGHT);//self.view.bounds;  
  254.         self.captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;  
  255.         [self.view.layer addSublayer: self.captureVideoPreviewLayer];  
  256.           
  257.         self.isScanning = YES;  
  258.         [self.captureSession startRunning];  
  259.           
  260.           
  261.     }else{  
  262.         dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);  
  263.         [captureOutput setSampleBufferDelegate:self queue:queue];          
  264.         NSString* key = (NSString *)kCVPixelBufferPixelFormatTypeKey;  
  265.         NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];  
  266.         NSDictionary *videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];  
  267.         [captureOutput setVideoSettings:videoSettings];  
  268.         [self.captureSession addOutput:captureOutput];  
  269.           
  270.         NSString* preset = 0;  
  271.         if (NSClassFromString(@"NSOrderedSet") && // Proxy for "is this iOS 5" ...  
  272.             [UIScreen mainScreen].scale > 1 &&  
  273.             [inputDevice  
  274.              supportsAVCaptureSessionPreset:AVCaptureSessionPresetiFrame960x540]) {  
  275.                 // NSLog(@"960");  
  276.                 preset = AVCaptureSessionPresetiFrame960x540;  
  277.             }  
  278.         if (!preset) {  
  279.             // NSLog(@"MED");  
  280.             preset = AVCaptureSessionPresetMedium;  
  281.         }  
  282.         self.captureSession.sessionPreset = preset;  
  283.           
  284.         if (!self.captureVideoPreviewLayer) {  
  285.             self.captureVideoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];  
  286.         }  
  287.         // NSLog(@"prev %p %@", self.prevLayer, self.prevLayer);  
  288.         self.captureVideoPreviewLayer.frame = CGRectMake(0, 0, WIDTH, HEIGHT);//self.view.bounds;  
  289.         self.captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;  
  290.         [self.view.layer addSublayer: self.captureVideoPreviewLayer];  
  291.           
  292.         self.isScanning = YES;  
  293.         [self.captureSession startRunning];  
  294.           
  295.           
  296.     }  
  297.       
  298.       
  299. }  
  300.   
  301. - (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer  
  302. {  
  303.     CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);  
  304.     // Lock the base address of the pixel buffer  
  305.     CVPixelBufferLockBaseAddress(imageBuffer,0);  
  306.       
  307.     // Get the number of bytes per row for the pixel buffer  
  308.     size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);  
  309.     // Get the pixel buffer width and height  
  310.     size_t width = CVPixelBufferGetWidth(imageBuffer);  
  311.     size_t height = CVPixelBufferGetHeight(imageBuffer);  
  312.       
  313.     // Create a device-dependent RGB color space  
  314.     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();  
  315.     if (!colorSpace)  
  316.     {  
  317.         NSLog(@"CGColorSpaceCreateDeviceRGB failure");  
  318.         return nil;  
  319.     }  
  320.       
  321.     // Get the base address of the pixel buffer  
  322.     void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);  
  323.     // Get the data size for contiguous planes of the pixel buffer.  
  324.     size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);  
  325.       
  326.     // Create a Quartz direct-access data provider that uses data we supply  
  327.     CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, baseAddress, bufferSize,  
  328.                                                               NULL);  
  329.     // Create a bitmap image from data supplied by our data provider  
  330.     CGImageRef cgImage =  
  331.     CGImageCreate(width,  
  332.                   height,  
  333.                   8,  
  334.                   32,  
  335.                   bytesPerRow,  
  336.                   colorSpace,  
  337.                   kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,  
  338.                   provider,  
  339.                   NULL,  
  340.                   true,  
  341.                   kCGRenderingIntentDefault);  
  342.     CGDataProviderRelease(provider);  
  343.     CGColorSpaceRelease(colorSpace);  
  344.       
  345.     // Create and return an image object representing the specified Quartz image  
  346.     UIImage *image = [UIImage imageWithCGImage:cgImage];  
  347.       
  348.     return image;  
  349. }  
  350.   
  351. #pragma mark 對影象進行解碼  
  352. - (void)decodeImage:(UIImage *)image  
  353. {  
  354.       
  355.     self.isScanning = NO;  
  356.     ZBarSymbol *symbol = nil;  
  357.       
  358.     ZBarReaderController* read = [ZBarReaderController new];  
  359.       
  360.     read.readerDelegate = self;  
  361.       
  362.     CGImageRef cgImageRef = image.CGImage;  
  363.       
  364.     for(symbol in [read scanImage:cgImageRef])break;  
  365.       
  366.     if (symbol!=nil) {  
  367.         if (timer) {  
  368.             [timer invalidate];  
  369.             timer=nil;  
  370.         }  
  371.           
  372.         _line.frame = CGRectMake((WIDTH-220)/2, 70, 220, 2);  
  373.         num = 0;  
  374.         upOrdown = NO;  
  375.         self.ScanResult(symbol.data,YES);  
  376.         [self.captureSession stopRunning];  
  377.         [self dismissViewControllerAnimated:YES completion:nil];  
  378.     }else{  
  379.         timer = [NSTimer scheduledTimerWithTimeInterval:.02 target:self selector:@selector(animation1) userInfo:nil repeats:YES];  
  380.         num = 0;  
  381.         upOrdown = NO;  
  382.         self.isScanning = YES;  
  383.         [self.captureSession startRunning];  
  384.   
  385.     }  
  386.       
  387.       
  388.       
  389. }  
  390. #pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate  
  391.   
  392. - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection  
  393. {  
  394.       
  395.     UIImage *image = [self imageFromSampleBuffer:sampleBuffer];  
  396.       
  397.     [self decodeImage:image];  
  398. }  
  399. #pragma mark AVCaptureMetadataOutputObjectsDelegate//IOS7下觸發  
  400. - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection  
  401. {  
  402.       
  403.       
  404.     if (metadataObjects.count>0)  
  405.     {  
  406.         AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];  
  407.         self.ScanResult(metadataObject.stringValue,YES);  
  408.     }  
  409.       
  410.     [self.captureSession stopRunning];  
  411.     _line.frame = CGRectMake((WIDTH-220)/2, 70, 220, 2);  
  412.     num = 0;  
  413.     upOrdown = NO;  
  414.     [self dismissViewControllerAnimated:YES completion:nil];  
  415.       
  416.       
  417. }  
  418.   
  419.   
  420.   
  421. #pragma mark - UIImagePickerControllerDelegate  
  422.   
  423. - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info  
  424. {  
  425.     if (timer) {  
  426.         [timer invalidate];  
  427.         timer=nil;  
  428.     }  
  429.     _line.frame = CGRectMake((WIDTH-220)/2, 70, 220, 2);  
  430.     num = 0;  
  431.     upOrdown = NO;  
  432.     UIImage *image = [info objectForKey:@"UIImagePickerControllerEditedImage"];  
  433.     [self dismissViewControllerAnimated:YES completion:^{[self decodeImage:image];}];  
  434.       
  435.       
  436. }  
  437.   
  438. - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker  
  439. {  
  440.     if (timer) {  
  441.         [timer invalidate];  
  442.         timer=nil;  
  443.     }  
  444.     _line.frame = CGRectMake((WIDTH-220)/2, 70, 220, 2);  
  445.     num = 0;  
  446.     upOrdown = NO;  
  447.     timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(animation1) userInfo:nil repeats:YES];  
  448.     [self dismissViewControllerAnimated:YES completion:^{  
  449.         self.isScanning = YES;  
  450.         [self.captureSession startRunning];  
  451.     }];  
  452. }  
  453.   
  454. #pragma mark - DecoderDelegate  
  455.   
  456.   
  457.   
  458. +(NSString*)zhengze:(NSString*)str  
  459. {  
  460.       
  461.     NSError *error;  
  462.     //http+:[^\\s]* 這是檢測網址的正規表示式  
  463.     NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"http+:[^\\s]*" options:0 error:&error];//篩選  
  464.       
  465.     if (regex != nil) {  
  466.         NSTextCheckingResult *firstMatch = [regex firstMatchInString:str options:0 range:NSMakeRange(0, [str length])];  
  467.           
  468.         if (firstMatch) {  
  469.             NSRange resultRange = [firstMatch rangeAtIndex:0];  
  470.             //從urlString中擷取資料  
  471.             NSString *result1 = [str substringWithRange:resultRange];  
  472.             NSLog(@"正則表達後的結果%@",result1);  
  473.             return result1;  
  474.               
  475.         }  
  476.     }  
  477.     return nil;  
  478. }  
  479. +(void)createImageWithImageView:(UIImageView*)imageView String:(NSString*)str Scale:(CGFloat)scale{  
  480.     CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];  
  481.     [filter setDefaults];  
  482.       
  483.     NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];  
  484.     [filter setValue:data forKey:@"inputMessage"];  
  485.       
  486.     CIImage *outputImage = [filter outputImage];  
  487.       
  488.     CIContext *context = [CIContext contextWithOptions:nil];  
  489.     CGImageRef cgImage = [context createCGImage:outputImage  
  490.                                        fromRect:[outputImage extent]];  
  491.       
  492.     UIImage *image = [UIImage imageWithCGImage:cgImage  
  493.                                          scale:1.0  
  494.                                    orientation:UIImageOrientationUp];  
  495.       
  496.     UIImage *resized = nil;  
  497.     CGFloat width = image.size.width*scale;  
  498.     CGFloat height = image.size.height*scale;  
  499.       
  500.     UIGraphicsBeginImageContext(CGSizeMake(width, height));  
  501.     CGContextRef context1 = UIGraphicsGetCurrentContext();  
  502.     CGContextSetInterpolationQuality(context1, kCGInterpolationNone);  
  503.     [image drawInRect:CGRectMake(0, -50, width, height)];  
  504.     resized = UIGraphicsGetImageFromCurrentImageContext();  
  505.     UIGraphicsEndImageContext();  
  506.     imageView.image = resized;  
  507.     CGImageRelease(cgImage);  
  508.   
  509. }  
  510. - (void)didReceiveMemoryWarning  
  511. {  
  512.     [super didReceiveMemoryWarning];  
  513.     // Dispose of any resources that can be recreated.  
  514. }  
  515.   
  516. /* 
  517. #pragma mark - Navigation 
  518.  
  519. // In a storyboard-based application, you will often want to do a little preparation before navigation 
  520. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
  521. { 
  522.     // Get the new view controller using [segue destinationViewController]. 
  523.     // Pass the selected object to the new view controller. 
  524. } 
  525. */  
  526.   
  527. ////支援旋轉  
  528. //-(BOOL)shouldAutorotate{  
  529. //    return NO;  
  530. //}  
  531. ////支援的方向  
  532. //- (UIInterfaceOrientationMask)supportedInterfaceOrientations {  
  533. //    return UIInterfaceOrientationMaskPortrait;  
  534. //}  
  535.   
  536. @end  

------------2.5AppController.h中新增程式碼:

  1. //獲取當前正在顯示的ViewController  
  2. + (UIViewController *)getCurrentVC;  
  3. //獲取當前螢幕中present出來的viewcontroller。  
  4. - (UIViewController *)getPresentedViewController;  
  5. //掃描二維碼  
  6. +(void)scanQRCode:(NSDictionary *)info;  

------------2.5AppController.mm中新增程式碼:

  1. //獲取當前正在顯示的ViewController  
  2. + (UIViewController *)getCurrentVC  
  3. {  
  4.     UIViewController *result = nil;  
  5.       
  6.     UIWindow * window = [[UIApplication sharedApplication] keyWindow];  
  7.     if (window.windowLevel != UIWindowLevelNormal)  
  8.     {  
  9.         NSArray *windows = [[UIApplication sharedApplication] windows];  
  10.         for(UIWindow * tmpWin in windows)  
  11.         {  
  12.             if (tmpWin.windowLevel == UIWindowLevelNormal)  
  13.             {  
  14.                 window = tmpWin;  
  15.                 break;  
  16.             }  
  17.         }  
  18.     }  
  19.   
  20.     UIView *frontView = [[window subviews] objectAtIndex:0];  
  21.     id nextResponder = [frontView nextResponder];  
  22.       
  23.     if ([nextResponder isKindOfClass:[UIViewController class]])  
  24.         result = nextResponder;  
  25.     else  
  26.         result = window.rootViewController;  
  27.       
  28.     return result;  
  29. }  
  30. //獲取當前螢幕中present出來的viewcontroller。  
  31. - (UIViewController *)getPresentedViewController  
  32. {  
  33.     UIViewController *appRootVC = [UIApplication sharedApplication].keyWindow.rootViewController;  
  34.     UIViewController *topVC = appRootVC;  
  35.     if (topVC.presentedViewController) {  
  36.         topVC = topVC.presentedViewController;  
  37.     }  
  38.       
  39.     return topVC;  
  40. }  
  41.   
  42. +(void) scanQRCode:(NSDictionary *)info  
  43. {  
  44.     int _callBack = [[info objectForKey:@"listener"] intValue];  
  45.       
  46. //    SGScanningQRCodeVC *scanningQRCodeVC = [[SGScanningQRCodeVC alloc] init];  
  47. //    [scanningQRCodeVC setupScanningQRCode];  
  48.       
  49.     UIViewController *nowViewController = [self getCurrentVC];  
  50.       
  51.     ZCZBarViewController*vc=[[ZCZBarViewController alloc]initWithIsQRCode:NO Block:^(NSString *result, BOOL isFinish) {  
  52.         if (isFinish) {  
  53.             NSLog(@"最後的結果%@",result);  
  54.             UIViewController *nowViewController = [self getCurrentVC];  
  55.             dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.02 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{  
  56.                 [nowViewController dismissViewControllerAnimated:NO completion:nil];  
  57.                   
  58.                 cocos2d::LuaBridge::pushLuaFunctionById(_callBack);  
  59.                 cocos2d::LuaValueDict dict;  
  60.                 dict["scanResult"] = cocos2d::LuaValue::stringValue([result UTF8String]);  
  61.                 cocos2d::LuaBridge::getStack()->pushLuaValueDict(dict);  
  62.                 cocos2d::LuaBridge::getStack()->executeFunction(1);  
  63.                 cocos2d::LuaBridge::releaseLuaFunctionById(_callBack);  
  64.             });  
  65.         }  
  66.     }];  
  67.     [nowViewController presentViewController:vc animated:YES completion:nil];  
  68. }  

其中scanQRCode方法為最終lua掉用oc的方法,在掃描識別出二維碼資訊之後會將資訊傳回給lua端。

------------2.6lua掉用oc掃描二維碼程式碼:

  1. local callBack = function (message)  
  2.     print("message scanResult : ", message.scanResult)  
  3.     Utils.showTip(message.scanResult)  
  4. end  
  5. local info = {listener = callBack}  
  6. luaoc.callStaticMethod("AppController""scanQRCode", info)  

------------2.7新增依賴框架
如上1.4,掃描二維碼需要新增框架AVFoundation, CoreMedie, CoreVideo, QuartzCore, libiconv

-----3.掃描介面橫豎屏說明

如果遊戲介面是橫屏的,而二維碼掃描介面要求是豎屏的,則需要做些操作。

------------3.1增加豎屏支援

專案->TARGETS->General->Deployment Info->Device Orientation->勾選Portrait,Landscape Left, Landscape Right。

------------3.2讓遊戲介面只支援橫屏

專案->frameworks->runtime-src->proj.ios_mac->ios->RootViewController.mmsupportedInterfaceOrientations方法修改為:

  1. // For ios6, use supportedInterfaceOrientations & shouldAutorotate instead  
  2. - (NSUInteger) supportedInterfaceOrientations{  
  3.     return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;  
  4. //#ifdef __IPHONE_6_0  
  5. //    return UIInterfaceOrientationMaskAllButUpsideDown;  
  6. //#endif  
  7. }  

------------3.3掃描二維碼介面只支援豎屏

專案->frameworks->runtime-src->proj.ios_mac->ios->ZCZBarViewController.mm中增加程式碼

  1. ////支援旋轉  
  2. //-(BOOL)shouldAutorotate{  
  3. //    return NO;  
  4. //}  
  5. ////支援的方向  
  6. //- (UIInterfaceOrientationMask)supportedInterfaceOrientations {  
  7. //    return UIInterfaceOrientationMaskPortrait;  
  8. //}  

------------3.4修改view介面width和height重新適配
專案->frameworks->runtime-src->proj.ios_mac->ios->ZCZBarViewController.mm中將

#define WIDTH#define HEIGHT兩個巨集的值顛倒下

-----4.關於專案->frameworks->runtime-src->proj.ios_mac->ios->ZCZBarViewController.mm#define WIDTH#define HEIGHT兩個巨集

本來因該是

#define WIDTH [UIScreen mainScreen].bounds.size.width

#define HEIGHT [UIScreen mainScreen].bounds.size.height

但在iphone4s(ios6.1.3)上取出的width和height為320, 480,而在iPhone6 Plus(ios10.2)上width和height為568, 320。

一個寬小於高,一個寬大於高,使得4s橫屏的時候,6Plus豎屏是對的,而在6Plus上橫屏就是亂的。

所以後來將兩個巨集修改為(注意:兩邊一定要帶括號,防止編譯時巨集展開後由於操作符優先順序導致的運算錯誤)

#define WIDTH ( ([UIScreen mainScreen].bounds.size.width>[UIScreen mainScreen].bounds.size.height)?[UIScreen mainScreen].bounds.size.width:[UIScreen mainScreen].bounds.size.height )
#define 
HEIGHT ( ([UIScreen mainScreen].bounds.size.width<[UIScreen mainScreen].bounds.size.height)?[UIScreen mainScreen].bounds.size.width:[UIScreen mainScreen].bounds.size.height )

從而將固定取獲得的二者較大值為二者較小值。若是豎屏,則反過來。

-----5.遇到的一些問題

------------5.1對於ZCZBarViewController.mm中的initCpture方法中有句

AVAuthorizationStatus authStatus = [AVCaptureDeviceauthorizationStatusForMediaType:mediaType];

注意:此方法只對ios7以上的系統有用,如果是在ios6的系統的話就直接崩潰了,況且ios6上也沒有“設定--隱私--相機”那一項。

所以加了if(IOS7)的判斷。

------------5.2若碰到錯誤Cannot synthesize weak property in file using manual reference counting 
專案->TARGETS->Build Settings->Apple LLVM 8.0-Language-Objective C->Weak References in Manual Retian Release改為YES

------------5.3編譯報錯XXXX.o

若編譯執行報錯,XXXX.o什麼什麼的問題,則可能是有依賴框架沒有匯入。

-----6.參考連結

//原生生成二維碼

http://blog.csdn.net/zhuming3834/article/details/50832953

//原生二維碼掃描

http://www.cocoachina.com/ios/20161009/17696.html

//zBar下載地址

http://download.csdn.net/download/kid_devil/7552613

//zBarDemo下載地址

http://download.csdn.net/detail/shan1991fei/9474417

//二維碼掃描之zXing與zBar的優劣

http://blog.csdn.net/l_215851356/article/details/51898514

相關文章