cocos2dx-lua在ios上实现生成及扫描二维码


首先说明下,我是支持用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中添加代码:

[cpp]  view plain  copy
  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中添加代码:

[cpp]  view plain  copy
  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方法,并显示

[cpp]  view plain  copy
  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代码:

[cpp]  view plain  copy
  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代码:

[cpp]  view plain  copy
  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中添加代码:

[cpp]  view plain  copy
  1. //获取当前正在显示的ViewController  
  2. + (UIViewController *)getCurrentVC;  
  3. //获取当前屏幕中present出来的viewcontroller。  
  4. - (UIViewController *)getPresentedViewController;  
  5. //扫描二维码  
  6. +(void)scanQRCode:(NSDictionary *)info;  

------------2.5AppController.mm中添加代码:

[cpp]  view plain  copy
  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扫描二维码代码:

[cpp]  view plain  copy
  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方法修改为:

[cpp]  view plain  copy
  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中增加代码

[cpp]  view plain  copy
  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://www.voidcn.com/article/p-zcstxcne-dx.html

//原生二维码扫描

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

相关文章
相关标签/搜索