iOS原生二维码/条形码相关
2016-12-02 16:53
197 查看
一. 二维码/条形码扫描
iOS7以后AVFoundation框架可以实现二维码的扫描,首先介绍一下AVFoundation框架是如何实现此功能的:
AVFoundation是一个很大的基础库,用来创建基于时间的视听媒体,可以用它来创建,检查,编辑媒体文件也可以输入流从设备和操作视频实时捕捉和回放,详细框架可以到官网去查看About AVFoundation。下面主要介绍如何运用AVFoundation来扫描二维码;
首先获取流媒体信息我们需要用AVCaptureSession这样的一个对象来管理输入流和输出流,AVCaptureVideoPreviewsLayer对象来显示信息。基本流程:
AVCaptureSession 管理输入(AVCaptureInput)和输出(AVCaptureOutput)流,包含开启和停止会话方法。
AVCaptureDeviceInput 是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。
AVCaptureDevice 代表了物理捕获设备如:摄像机。用于配置等底层硬件设置相机的自动对焦模式。
AVCaptureMetadataOutput 是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。
AVCaptureVideoPreviewLayer CALayer的一个子类,显示捕获到的相机输出流
二维码扫描
二维码自定义扫描界面
代码实现:
二. 生成二维码图片
三. 解析二维码图片
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 bc3a ; 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 原生二维码、条形码扫描for IOS7 (八)
- ios 条形码、二维码读取相关
- iOS 原生的二维码/条形码扫描
- iOS 原生实现扫描二维码和条形码功能限制扫描区域
- iOS系统原生二维码条形码扫描
- [iOS 原生代码实现扫描二维码/条形码] AVCaptureDevice
- iOS系统原生二维码条形码扫描
- IOS开发使用原生框架,二维码(条形码)的生成与扫描(支持长按扫描),可控制闪光灯
- 使用AVFoundation实现iOS原生二维码、条形码扫描(可限制扫描范围、可手动调节焦距)
- 【iOS】AVFoundation架构下的原生二维码和条形码扫描
- iOS 7以上原生二维码、条码扫描(ZXingObjC相册读取)
- 使用ZbarSDK实现扫描二维码以及条形码功能(iOS)
- 关于iOS原生条形码扫描,你需要注意的两三事
- ios 摄像头,二维码相关
- iOS- 详解如何使用ZBarSDK集成扫描二维码/条形码
- IOS上原生代码实现二维码扫描功能
- iOS开发——iOS7(及以后版本) SDK自带二维码(含条形码)扫码、二维码生成
- 在iOS中使用ZBar扫描二维码和条形码
- 关于iOS原生条形码扫描,你需要注意的两三事