zoukankan      html  css  js  c++  java
  • iOS 二维码 学习

    这段时间忙着交接工作,找工作,找房子,入职,杂七杂八的,差不多一个月没有静下来学习了.这周末晚上等外卖的时间学习一下二维码的制作与扫描.

    项目采用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

    效果如下:

         

                                                                                                                           

  • 相关阅读:
    AIX6.1 线程模型说明
    多线程专题之线程死锁原因之谜
    多线程执行顺序诡异现象谈,你不知道的pthread_create
    SOA体系结构基础培训教程-规范标准篇
    C# AES要解密的数据的长度无效
    winform命名规范
    winform 打开一个窗体,关闭一个窗体
    VS2017专业版和企业版激活密钥
    AES五种加密模式
    c#POST请求php接口
  • 原文地址:https://www.cnblogs.com/shaoting/p/7899777.html
Copyright © 2011-2022 走看看