您的位置:首页 > 移动开发 > IOS开发

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的一个子类,显示捕获到的相机输出流

二维码扫描

二维码自定义扫描界面

代码实现:

- (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;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: