iOS原生二维码/条形码相关
来源:互联网 发布:qq邮箱smtp设置 端口 编辑:程序博客网 时间:2024/05/20 18:46
一. 二维码/条形码扫描
iOS7以后AVFoundation框架可以实现二维码的扫描,首先介绍一下AVFoundation框架是如何实现此功能的:
AVFoundation是一个很大的基础库,用来创建基于时间的视听媒体,可以用它来创建,检查,编辑媒体文件也可以输入流从设备和操作视频实时捕捉和回放,详细框架可以到官网去查看About AVFoundation。下面主要介绍如何运用AVFoundation来扫描二维码;
首先获取流媒体信息我们需要用AVCaptureSession这样的一个对象来管理输入流和输出流,AVCaptureVideoPreviewsLayer对象来显示信息。基本流程:
AVCaptureSession 管理输入(AVCaptureInput)和输出(AVCaptureOutput)流,包含开启和停止会话方法。
AVCaptureDeviceInput 是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。
AVCaptureDevice 代表了物理捕获设备如:摄像机。用于配置等底层硬件设置相机的自动对焦模式。
AVCaptureMetadataOutput 是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。
AVCaptureVideoPreviewLayer CALayer的一个子类,显示捕获到的相机输出流
二维码扫描
二维码自定义扫描界面
代码实现:
- (void)createScanQRCode { // 1. 创建捕捉会话 self.captureSession = [[AVCaptureSession alloc] init]; // 2. 添加输入设备 AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil]; [self.captureSession addInput:input]; // 3. 添加输出数据 AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init]; // 设置代理 [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; [self.captureSession addOutput:output]; // 设置输入元数据的类型 // AVMetadataObjectTypeQRCode 二维码 [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code]]; // 这句代码又放在添加输出数据(addOutPut: )之后,否则会报错 // 设置扫描区域 // 此属性坐标系平常设置的坐标系是完全相反的,即X与Y互换、W与H互换。 [output setRectOfInterest:CGRectMake(80 / kScreenHeight, 50 / kScreenWidth, (kScreenWidth - 100) / kScreenHeight, (kScreenWidth - 100) / kScreenWidth)]; // 4. 添加扫描图层 self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession]; self.previewLayer.frame = self.view.bounds; [self.view.layer insertSublayer:self.previewLayer atIndex:0]; // 5. 开始扫描 [self.captureSession startRunning]; // 设置扫描区域的动画效果 [self scanWindowAnimation];}
// 设置扫描区域的动画效果()- (void)scanWindowAnimation { if (self.isScan) { [UIView animateWithDuration:10 animations:^{ self.lineView.frame = CGRectMake(50, 80 + kScreenWidth - 100, kScreenWidth - 100, 1); } completion:^(BOOL finished) { self.lineView.frame = CGRectMake(50, 80, kScreenWidth - 100, 1); [self scanWindowAnimation]; }]; }}
#pragma mark - AVCaptureMetadataOutputObjectsDelegate 实现output的回调方法// 当扫描到数据时就会执行该方法- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { self.isScan = NO; NSLog(@"%@", [NSThread currentThread]); if (metadataObjects.count > 0) { AVMetadataMachineReadableCodeObject *object = [metadataObjects lastObject]; NSLog(@"%@", object.stringValue); // 停止扫描 [self.captureSession stopRunning]; // 将预览图层移除 [self.previewLayer removeFromSuperlayer]; } else { NSLog(@"没有扫描到数据"); }}
二. 生成二维码图片
/** 生成二维码图片 @param QRString 二维码内容 @param sizeWidth 图片宽度(正方形) @param color 填充色 @return 二维码图片 */+ (UIImage *)createQRImageString:(NSString *)QRString sizeWidth:(CGFloat)sizeWidth fillColor:(UIColor *)color;
#pragma mark - 生成二维码图片+ (UIImage *)createQRImageString:(NSString *)QRString sizeWidth:(CGFloat)sizeWidth fillColor:(UIColor *)color { CIImage *ciImage = [self createQRForString:QRString]; UIImage *qrCode = [self createNonInterpolatedUIImageFromCIImage:ciImage withSize:sizeWidth]; if (color) { CGFloat R, G, B; CGColorRef colorRef = [color CGColor]; long numComponents = CGColorGetNumberOfComponents(colorRef); if (numComponents == 4) { const CGFloat *components = CGColorGetComponents(colorRef); R = components[0] * 255.0f; G = components[1] * 255.0f; B = components[2] * 255.0f; } UIImage *customQrcode = [self imageBlackToTransparent:qrCode withRed:R green:G blue:B]; return customQrcode; } return qrCode;}
#pragma mark - QRCodeGenerator+ (CIImage *)createQRForString:(NSString *)qrString { // 将字符串转换为data数据 NSData *strData = [qrString dataUsingEncoding:NSUTF8StringEncoding]; // 创建filter CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; // 设置内容和纠错类别 [qrFilter setValue:strData forKey:@"inputMessage"]; [qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"]; // 返回CIImage return qrFilter.outputImage;}
#pragma mark - InterpolatedUIImage// 将CIImage转换为UIImage+ (UIImage *)createNonInterpolatedUIImageFromCIImage:(CIImage *)image withSize:(CGFloat)size { CGRect extent = CGRectIntegral(image.extent); CGFloat scale = MIN(size / CGRectGetWidth(extent), size / CGRectGetHeight(extent)); // 创建bitmap size_t width = CGRectGetWidth(extent) * scale; size_t height = CGRectGetHeight(extent) *scale; CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray(); CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone); CIContext *context = [CIContext contextWithOptions:nil]; CGImageRef bitmapImage = [context createCGImage:image fromRect:extent]; CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone); CGContextScaleCTM(bitmapRef, scale, scale); CGContextDrawImage(bitmapRef, extent, bitmapImage); // 保存bitmap到图片 CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef); // 释放 CGContextRelease(bitmapRef); CGImageRelease(bitmapImage); return [UIImage imageWithCGImage:scaledImage];}
#pragma mark - imageToTransparent// 对二维码颜色进行填充void ProvideReleaseData (void *info, const void *data, size_t size) { free((void *)data);}+ (UIImage *)imageBlackToTransparent:(UIImage *)image withRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue { const int imageWidth = image.size.width; const int imageHeight = image.size.height; size_t bytesPerRow = imageWidth * 4; uint32_t *rgbImageBuf = (uint32_t *)malloc(bytesPerRow * imageHeight); // 创建上下文 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast); CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage); // 遍历像素 int pixelNum = imageWidth * imageHeight; uint32_t *pCurPtr = rgbImageBuf; for (int i = 0; i < pixelNum; i++, pCurPtr++) { if ((*pCurPtr & 0xFFFFFF00) < 0x99999900) { // 改变颜色 uint8_t *ptr = (uint8_t *)pCurPtr; ptr[3] = red; // 0~255 ptr[2] = green; ptr[1] = blue; } else { uint8_t *ptr = (uint8_t *)pCurPtr; ptr[0] = 0; } } // 输出图片 CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight, ProvideReleaseData); CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight, 8, 32, bytesPerRow, colorSpace, kCGImageAlphaLast | kCGBitmapByteOrder32Little, dataProvider, NULL, true, kCGRenderingIntentDefault); CGDataProviderRelease(dataProvider); UIImage *resultUIImage = [UIImage imageWithCGImage:imageRef]; // 清理空间 CGImageRelease(imageRef); CGContextRelease(context); CGColorSpaceRelease(colorSpace); return resultUIImage;}
三. 解析二维码图片
#pragma mark - 读取图片二维码+ (NSString *)readQRCodeFromImage:(UIImage *)image { NSData *data = UIImagePNGRepresentation(image); CIImage *ciImage = [CIImage imageWithData:data]; if (ciImage) { CIDetector *qrDetector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:[CIContext contextWithOptions:@{kCIContextUseSoftwareRenderer:@(YES)}] options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}]; NSArray *resultArray = [qrDetector featuresInImage:ciImage]; if (resultArray.count > 0) { CIFeature *feature = resultArray[0]; CIQRCodeFeature *qrFeature = (CIQRCodeFeature *)feature; NSString *result = qrFeature.messageString; return result; } else { return nil; } } else { return nil; }}
- iOS原生二维码/条形码相关
- iOS系统原生二维码条形码扫描
- iOS系统原生二维码条形码扫描
- iOS 原生的二维码/条形码扫描
- 【iOS】AVFoundation架构下的原生二维码和条形码扫描
- IOS开发UI进阶篇 — 原生二维码、条形码扫描
- IOS 原生二维码、条形码扫描for IOS7 (八)
- iOS原生二维码生成与扫描以及条形码的扫描
- [iOS 原生代码实现扫描二维码/条形码] AVCaptureDevice
- iOS原生条形码扫描
- iOS原生条形码扫描
- iOS 二维码,条形码扫描
- IOS扫描二维码条形码
- ios 二维码、条形码扫描
- iOS 条形码、二维码心得
- 原生二维码和条形码扫描代码
- OC - 原生扫码(扫描二维码,条形码)
- 使用AVFoundation实现iOS原生二维码、条形码扫描(可限制扫描范围、可手动调节焦距)
- Java中 Buffer的作用
- intellid idea安装plantUML插件以及错误解决
- 基于7系列FPGA的DCI技术的应用
- Lambda学习
- 深入openstack rpm打包原理(openstack cinder rpm打包完全分析)
- iOS原生二维码/条形码相关
- ros 与 sony ps3joy
- hadoop PipeMapRed faild
- STM32 NVIC中断优先级管理
- Elastic-JOB 开发指南
- POJ 1317 Do the Untwist 已被翻译
- Java实现进度条JProgressBar设置颜色,变色进度条
- 编码中的setCharacterEncoding 理解
- Jmeter 分布式