技术分享之二维码开发

二维码的介绍

  • 二维条码/二维码是用某种特定的几何图形按一定规律在平面分布的黑白相间的图形记录数据符号信息的
  • 总结: 用图形记录标记一些信息,方便通过图形识别来获取信息
  • 应用场景
    • 信息获取(名片、地图、WIFI密码、资料)
    • 手机电商(用户扫码、手机直接购物下单)
    • 手机支付(扫描商品二维码,通过银行或第三方支付提供的手机端通道完成支付)
    • 微信添加好友
  • 二维码开发
    • 二维码的生成
    • 二维码的识别
      • 从图片中识别二维码,并且获取信息
      • 扫描二维码,识别二维码中的信息
  • 最终封装下载地址:
    • https://github.com/coderwhy/QRCodeDemo

二维码的生成

  • 生成二维码的方式
    • 采用第三方框架(放弃)
      • ZXing/ZBar
      • 框架不支持64位(2015年2月1号起, 不允许不支持64位处理器的APP 上架)
    • 系统自带API
  • 生成二维码的步骤
    • 创建滤镜
      • 属于CoreImage框架,该框架经常用于处理图片(比如毛比例效果/生成二维码)
    • 设置输入的内容
      • 必须为NSData类型
    • 获取输出的图片
      • 是CIImage类型的图片
    • 放大图片,并且进行显示
  • 代码实现
#pragma mark - 生成二维码
- (IBAction)generateQRCode {
    // 1.创建滤镜
    CIFilter * filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];

    // 2.设置滤镜的输入内容
    // 2.1.取出需要设置的内容
    NSString *inputContent = self.textField.text;

    // 2.2.设置内容
    NSData *inputData = [inputContent dataUsingEncoding:NSUTF8StringEncoding];
    [filter setValue:inputData forKey:@"inputMessage"];

    // 3.获取输出的图片
    CIImage *outputImage = filter.outputImage;

    // 4.放大图片
    CGAffineTransform scale = CGAffineTransformMakeScale(10, 10);
    outputImage = [outputImage imageByApplyingTransform:scale];

    // 5.显示图片
    self.imageView.image = [UIImage imageWithCIImage:outputImage];
}
  • 在二维码中添加前景图片和设置容错率
    • 容错率通过KVC设置
    • Key: inputCorrectionLevel
    • Value: L/M/Q/H
#pragma mark - 添加前景图片
- (UIImage *)appendForegroundImageWithOriginal:(UIImage *)originalImage foreground:(UIImage *)foregroundImage {
    // 1.获取原始图片的尺寸
    CGSize originalSize = originalImage.size;

    // 2.获取图片上下文
    UIGraphicsBeginImageContext(originalSize);

    // 3.将大图绘制到上下文中
    [originalImage drawInRect:CGRectMake(0, 0, originalSize.width, originalSize.height)];

    // 4.将小图绘制到上下文中
    CGFloat width = 80;
    CGFloat height = 80;
    CGFloat x = (originalSize.width - 80) * 0.5;
    CGFloat y = (originalSize.height - 80) * 0.5;
    [foregroundImage drawInRect:CGRectMake(x, y, width, height)];

    // 5.获取上下文中的图片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    // 6.关闭上下文
    UIGraphicsEndImageContext();

    return newImage;
}

识别图片中的二维码

  • 识别图片中二维码步骤

    • 创建探测器
      • 属于CoreImage框架(CIDetector)
    • 获取CIImage类型的图片
    • 获取图片中所有符合特征的内容(CIQRCodeFeature)
    • 遍历所有的特性(CIQRCodeFeature)
    • 获取特征中代表的信息(messageString)
  • 识别二维码的代码实现

#pragma mark - 识别图形中的二维码
- (IBAction)detectorQRCode {
    // 1.创建过滤器
    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:nil];

    // 2.创建CIImage对象
    CIImage *imageCI = [[CIImage alloc] initWithImage:self.imageView.image];

    // 3.获取识别到的所有结果
    NSArray *features = [detector featuresInImage:imageCI];

    // 4.遍历所有的结果
    NSMutableString *strM = [NSMutableString string];
    for (CIQRCodeFeature *f in features) {
        [strM appendString:f.messageString];
    }

    // 5.弹出弹窗显示结果
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"识别的信息" message:strM preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil];
    [alert addAction:action];
    [self presentViewController:alert animated:true completion:nil];
}

扫描二维码

  • 扫描二维码步骤
    • 创建输入设备(摄像头)
      • 获取摄像头设备
      • 创建输入对象
    • 创建输出设置(元数据)
      • 创建输出对象
      • 设置输出对象的代理(在代理中获取扫描到的数据)
      • 设置输出数据的类型
    • 创建捕捉会话
      • 将输入添加到会话中
      • 将输出添加到会话中
    • 添加预览图片(方便用于查看)
      • 创建图层,将图片添加到View图层中
    • 开始扫描
#pragma mark - 开始扫描
- (void)startScanning {
    // 1.创建输入设备(摄像头)
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];

    // 2.创建输入方式(Metadata)
    AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

    // 3.创建会话,将输入和输出联系起来
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
    [session addInput:input];
    [session addOutput:output];
    [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];

    // 4.创建会话图层
    AVCaptureVideoPreviewLayer *layer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    layer.frame = self.view.bounds;
    [self.view.layer insertSublayer:layer atIndex:0];
    self.layer = layer;

    // 5.开始扫描
    [session startRunning];

    // 6.设置扫描的区域
    CGSize size = [UIScreen mainScreen].bounds.size;
    CGFloat x = self.qrCodeView.frame.origin.y / size.height;
    CGFloat y = self.qrCodeView.frame.origin.x / size.width;
    CGFloat w = self.qrCodeView.frame.size.height / size.height;
    CGFloat h = self.qrCodeView.frame.size.width / size.width;
    output.rectOfInterest = CGRectMake(x, y, w, h);
}

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

    // 0.移除之前的绘制
    for (CAShapeLayer *layer in self.layers) {
        [layer removeFromSuperlayer];
    }

    // 1.获取扫描结果
    NSMutableString *resultMStr = [NSMutableString string];
    for (AVMetadataMachineReadableCodeObject *result in metadataObjects) {
        // 1.1.获取扫描到的字符串
        [resultMStr appendString:result.stringValue];

        // 1.2.绘制扫描到内容的边框
        [self drawEdgeBorder:result];
    }

    // 2.显示结果
    NSString *string = [resultMStr isEqualToString:@""] ? @"请将二维码放入输入框中" : resultMStr;
    self.resultLabel.text = string;
}

- (void)drawEdgeBorder:(AVMetadataMachineReadableCodeObject *)resultObjc {
    // 0.转化object
    resultObjc = (AVMetadataMachineReadableCodeObject *)[self.layer transformedMetadataObjectForMetadataObject:resultObjc];

    // 1.创建绘制的图层
    CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];

    // 2.设置图层的属性
    shapeLayer.fillColor = [UIColor clearColor].CGColor;
    shapeLayer.strokeColor = [UIColor blueColor].CGColor;
    shapeLayer.lineWidth = 5;

    // 3.创建贝塞尔曲线
    // 3.1.创建贝塞尔曲线
    UIBezierPath *path = [[UIBezierPath alloc] init];

    // 3.2.将path移动到起始位置
    int index = 0;
    for (id dict in resultObjc.corners) {
        // 3.2.1.获取点
        CGPoint point = CGPointZero;
        CGPointMakeWithDictionaryRepresentation((CFDictionaryRef)dict, &point);
        // NSLog(@"%@", NSStringFromCGPoint(point));
        // 3.2.2.判断如何使用该点
        if (index == 0) {
            [path moveToPoint:point];
        } else {
            [path addLineToPoint:point];
        }

        // 3.2.3.下标值自动加1
        index++;
    }

    // 3.3.关闭路径
    [path closePath];

    // 4.画出路径
    shapeLayer.path = path.CGPath;

    // 5.将layer添加到图册中
    [self.view.layer addSublayer:shapeLayer];

    // 6.添加到数组中
    [_layers addObject:shapeLayer];
}

- (NSMutableArray *)layers {
    if (_layers == nil) {
        _layers = [NSMutableArray array];
    }
    return _layers;
}

总结

  • 最后有将二维码所有的操作封装到工具栏中
  • 可以下载对应的代码查看
    • 代码地址:https://github.com/coderwhy/QRCodeDemo
  • 后续有时间会进行进一步封装,并且上传到Cocoapods
  • Thank you for your support !

你可能感兴趣的:(技术分享之二维码开发)