1. 程式人生 > >iOS 二維碼 學習

iOS 二維碼 學習

解析失敗 dev pin gre 通過 ecg created size_t little

這段時間忙著交接工作,找工作,找房子,入職,雜七雜八的,差不多一個月沒有靜下來學習了.這周末晚上等外賣的時間學習一下二維碼的制作與掃描.

項目采用OC語言,只要使用iOS自帶的CoreImage框架,通過濾鏡CIFilter生成二維碼,掃描使用原生自帶相機實現.

開擼:

先寫一個類,封裝把string轉換我image和把CIImage轉換為string:

QRImage.h

技術分享圖片
 1 //
 2 //  QRImage.h
 3 //  QRcode
 4 //
 5 //  Created by Shaoting Zhou on 2017/11/19.
 6 //  Copyright © 2017年 Shaoting Zhou. All rights reserved.
7 // 8 9 #import <Foundation/Foundation.h> 10 #import <CoreImage/CoreImage.h> 11 #import <UIKit/UIKit.h> 12 13 @interface QRImage : NSObject 14 15 + (UIImage *)imageWithQRString:(NSString *)string; //把string轉換我image 16 + (NSString *)stringFromCiImage:(CIImage *)ciimage; //把CIImage轉換為string
17 18 @end
View Code

QRImage.m

技術分享圖片
 1 //
 2 //  QRImage.m
 3 //  QRcode
 4 //
 5 //  Created by Shaoting Zhou on 2017/11/19.
 6 //  Copyright © 2017年 Shaoting Zhou. All rights reserved.
 7 //
 8 
 9 #import "QRImage.h"
10 
11 @implementation QRImage
12 
13 #pragma mark - 把string轉換為Image
14 + (UIImage *)imageWithQRString:(NSString *)string
{ 15 NSData * stringData = [string dataUsingEncoding:NSUTF8StringEncoding]; 16 17 CIFilter * qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; //過濾器 18 [qrFilter setValue:stringData forKey:@"inputMessage"]; 19 [qrFilter setValue:@"M" forKey:@"inputCorrectionLevel"]; //糾錯等級 20 UIImage * image = [self createUIImageFromCIImage:qrFilter.outputImage withSize:300]; 21 return image; 22 } 23 24 25 #pragma mark - CIImgae -> UIImage 26 + (UIImage *)createUIImageFromCIImage:(CIImage *)image withSize:(CGFloat)size{ 27 CGRect extent = CGRectIntegral(image.extent); 28 CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent)); 29 30 //1.創建bitmap; 31 size_t width = CGRectGetWidth(extent) * scale; 32 size_t height = CGRectGetHeight(extent) * scale; 33 CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray(); 34 CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone); 35 CIContext *context = [CIContext contextWithOptions:nil]; 36 CGImageRef bitmapImage = [context createCGImage:image fromRect:extent]; 37 CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone); 38 CGContextScaleCTM(bitmapRef, scale, scale); 39 CGContextDrawImage(bitmapRef, extent, bitmapImage); 40 41 //2.保存bitmap到圖片 42 CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef); 43 CGContextRelease(bitmapRef); 44 CGImageRelease(bitmapImage); 45 return [UIImage imageWithCGImage:scaledImage]; 46 47 } 48 49 50 #pragma mark - 把image轉換為string 51 + (NSString *)stringFromCiImage:(CIImage *)ciimage{ 52 NSString * content = nil; 53 if(!ciimage){ 54 return content; 55 } 56 CIDetector * detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:[CIContext contextWithOptions:nil] options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}]; 57 NSArray * features = [detector featuresInImage:ciimage]; 58 if(features.count){ 59 for (CIFeature * feature in features) { 60 if([feature isKindOfClass:[CIQRCodeFeature class]]){ 61 content = ((CIQRCodeFeature *)feature).messageString; 62 break; 63 } 64 } 65 }else{ 66 NSLog(@"解析失敗,確保硬件支持"); 67 } 68 69 return content; 70 } 71 @end
View Code

上面的代碼就是關鍵之處.

下面,寫一個界面生成二維碼,通過上面寫好的string轉換我image,顯示在屏幕之上.

MainViewController.h

技術分享圖片
 1 //
 2 //  MainViewController.h
 3 //  QRcode
 4 //
 5 //  Created by Shaoting Zhou on 2017/11/18.
 6 //  Copyright © 2017年 Shaoting Zhou. All rights reserved.
 7 //
 8 
 9 #import <UIKit/UIKit.h>
10 #import "QRImage.h"
11 #import "ScanViewController.h"
12 
13 @interface MainViewController : UIViewController
14 @property (nonatomic,strong) UIImageView * qrImageView;
15 @property (nonatomic,strong) UITextField * textField;
16 @end
View Code

MainViewController.m

技術分享圖片
 1 //
 2 //  MainViewController.m
 3 //  QRcode
 4 //
 5 //  Created by Shaoting Zhou on 2017/11/18.
 6 //  Copyright © 2017年 Shaoting Zhou. All rights reserved.
 7 //
 8 
 9 #import "MainViewController.h"
10 
11 @interface MainViewController ()
12 
13 @end
14 
15 @implementation MainViewController
16 
17 - (void)viewDidLoad {
18     [super viewDidLoad];
19     [self setUI];
20     self.title = @"生成二維碼";
21     
22     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"掃描" style:(UIBarButtonItemStylePlain) target:self action:@selector(scangQRimage)];
23 }
24 
25 -(void)setUI{
26     self.textField = [[UITextField alloc]initWithFrame:CGRectMake(10, 200, 200, 50)];
27     self.textField.borderStyle = UITextBorderStyleRoundedRect;
28     [self.view addSubview:self.textField];
29     
30     UIButton * btn = [[UIButton alloc]initWithFrame:CGRectMake(230, 200, 120, 50)];
31     [btn setTitle:@"生成二維碼" forState:(UIControlStateNormal)];
32     [btn setTitleColor:[UIColor redColor] forState:(UIControlStateNormal)];
33     [btn addTarget:self action:@selector(makeQRcode) forControlEvents:(UIControlEventTouchUpInside)];
34     [self.view addSubview:btn];
35     
36     self.qrImageView = [[UIImageView alloc]initWithFrame:CGRectMake(20, 300, 200, 200)];
37     [self.view addSubview:self.qrImageView];
38     
39     
40 }
41 #pragma mark - 生成二維碼
42 -(void)makeQRcode{
43     [self.textField resignFirstResponder];
44     UIImage * img = [QRImage imageWithQRString:self.textField.text];
45     self.qrImageView.image = img;
46 }
47 
48 #pragma mark - push到掃描界面
49 -(void)scangQRimage{
50     ScanViewController * scanVC = [[ScanViewController alloc]init];
51     [self.navigationController pushViewController:scanVC animated:NO];
52 }
53 
54 - (void)didReceiveMemoryWarning {
55     [super didReceiveMemoryWarning];
56     // Dispose of any resources that can be recreated.
57 }
58 
59 /*
60 #pragma mark - Navigation
61 
62 // In a storyboard-based application, you will often want to do a little preparation before navigation
63 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
64     // Get the new view controller using [segue destinationViewController].
65     // Pass the selected object to the new view controller.
66 }
67 */
68 
69 @end
View Code

再寫一個界面掃描二維碼和通過相冊選擇二維碼掃描,通過上面寫好的把CIImage轉換為string,掃描出二維碼信息顯示出來即可.

ScanViewController.h

技術分享圖片
 1 //
 2 //  ScanViewController.h
 3 //  QRcode
 4 //
 5 //  Created by Shaoting Zhou on 2017/11/19.
 6 //  Copyright © 2017年 Shaoting Zhou. All rights reserved.
 7 //
 8 
 9 #import <UIKit/UIKit.h>
10 #import <AVFoundation/AVFoundation.h>
11 #import "QRImage.h"
12 @interface ScanViewController : UIViewController <AVCaptureMetadataOutputObjectsDelegate,UINavigationControllerDelegate,UIImagePickerControllerDelegate>
13 @property (nonatomic,strong) AVCaptureSession * session;
14 @property (nonatomic,strong) UITextField * textField;
15 
16 @end
View Code

ScanViewController.m

技術分享圖片
  1 //
  2 //  ScanViewController.m
  3 //  QRcode
  4 //
  5 //  Created by Shaoting Zhou on 2017/11/19.
  6 //  Copyright © 2017年 Shaoting Zhou. All rights reserved.
  7 //
  8 
  9 #import "ScanViewController.h"
 10 
 11 @interface ScanViewController ()
 12 
 13 @end
 14 
 15 @implementation ScanViewController
 16 
 17 - (void)viewDidLoad {
 18     [super viewDidLoad];
 19     self.title = @"掃描二維碼";
 20     
 21     self.textField = [[UITextField alloc]initWithFrame:CGRectMake(10, 100, 200, 50)];
 22     self.textField.borderStyle = UITextBorderStyleRoundedRect;
 23     self.textField.userInteractionEnabled = NO;
 24     [self.view addSubview:self.textField];
 25     
 26     
 27     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"相冊" style:(UIBarButtonItemStylePlain) target:self action:@selector(presentImagePicker)];
 28     
 29     
 30 }
 31 - (void)viewWillAppear:(BOOL)animated{
 32     [super viewWillAppear:animated];
 33     [self startScan];
 34     
 35 }
 36 
 37 #pragma  mark - 開始掃描
 38 - (void)startScan{
 39     if([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] == AVAuthorizationStatusAuthorized || [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] == AVAuthorizationStatusNotDetermined ){
 40         self.session = [[AVCaptureSession alloc]init];
 41         AVCaptureDeviceInput * input = [[AVCaptureDeviceInput alloc]initWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] error:nil];
 42         if(input){
 43             [self.session addInput:input];
 44         }
 45         
 46         AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
 47         [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
 48         if(output){
 49             [self.session addOutput:output];
 50         }
 51         
 52         NSMutableArray * ary = [[NSMutableArray alloc]init];
 53         if([output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeQRCode]){
 54             [ary addObject:AVMetadataObjectTypeQRCode];
 55         }
 56         if([output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeEAN13Code]){
 57             [ary addObject:AVMetadataObjectTypeEAN13Code];
 58         }
 59         if([output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeEAN8Code]){
 60             [ary addObject:AVMetadataObjectTypeEAN8Code];
 61         }
 62         if([output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeCode128Code]){
 63             [ary addObject:AVMetadataObjectTypeCode128Code];
 64         }
 65         output.metadataObjectTypes = ary;
 66         
 67         AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
 68         layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
 69         layer.frame = CGRectMake((self.view.bounds.size.width - 300)/2, 164, 300, 300);
 70         [self.view.layer addSublayer:layer];
 71         
 72         UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake((self.view.bounds.size.width - 300)/2, 164, 300, 300)];
 73         
 74         [self.view addSubview:imageView];
 75         [self.session startRunning];
 76     }
 77 }
 78 
 79 #pragma mark - AVCaptureMetadataOutputObjectsDelegate代理方法
 80 - (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
 81     NSString * str = nil;
 82     for (AVMetadataObject * obj in metadataObjects) {
 83         if([obj.type isEqualToString:AVMetadataObjectTypeQRCode]){
 84             str = [(AVMetadataMachineReadableCodeObject *)obj stringValue];
 85             [self.session startRunning];
 86             break;
 87         }
 88     }
 89     self.textField.text = str;
 90 }
 91 
 92 #pragma mark - UIImagePickerControllerDelegate代理方法
 93 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
 94     UIImage * image = [info objectForKey:UIImagePickerControllerOriginalImage];
 95     
 96     CIImage * ciimage = [[CIImage alloc]initWithImage:image];
 97     NSString * str = [QRImage stringFromCiImage:ciimage];
 98     self.textField.text = str;
 99     [self dismissViewControllerAnimated:YES completion:nil];
100 }
101 
102 
103 #pragma mark - 彈出相冊
104 - (void)presentImagePicker{
105     UIImagePickerController * imagePicker = [[UIImagePickerController alloc]init];
106     imagePicker.delegate = self;
107     [self presentViewController:imagePicker animated:NO completion:nil];
108 }
109 
110 - (void)didReceiveMemoryWarning {
111     [super didReceiveMemoryWarning];
112     // Dispose of any resources that can be recreated.
113 }
114 
115 /*
116  #pragma mark - Navigation
117  
118  // In a storyboard-based application, you will often want to do a little preparation before navigation
119  - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
120  // Get the new view controller using [segue destinationViewController].
121  // Pass the selected object to the new view controller.
122  }
123  */
124 
125 @end
View Code

github: https://github.com/pheromone/QRcode

效果如下:

技術分享圖片

iOS 二維碼 學習