本文中使用的是系统原生coreimage,实现功能二维码扫描和解析和生成
======================二维码扫描和解析=============================
@interfaceScanViewController ()
@property (weak, nonatomic) IBOutletNSLayoutConstraint *topLayoutConstraint;
@property (nonatomic,strong) AVCaptureSession *codeCaptureSession;
@property (nonatomic,strong) AVCaptureVideoPreviewLayer *codeCaptureVideoPreviewLayer;@end
@implementation ScanViewController
#pragma mark - 进入相册- (IBAction)QRCodeFromPickeC:(id)sender {
UIImagePickerController *imagePC = [[UIImagePickerControlleralloc] init];
imagePC.delegate = self;
[selfpresentViewController:imagePC animated:YEScompletion:nil]; }
#pragma mark - 点击图片进行解析- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[picker dismissViewControllerAnimated:YEScompletion:nil];
NSData *data = UIImageJPEGRepresentation(info[UIImagePickerControllerOriginalImage], 1);
NSLog(@"%@",[selfstringFromCiImage:[CIImageimageWithData:data]]);
[selfaddAlertViewControllerWithMessage:[selfstringFromCiImage:[CIImageimageWithData:data]]];
}
#pragma mark - 解析图片
- (NSString *)stringFromCiImage:(CIImage *)ciimage {
NSString *content = @"" ;
if (!ciimage) {
return content;
}
CIDetector *detector = [CIDetectordetectorOfType:CIDetectorTypeQRCode
context:[CIContext contextWithOptions:nil]
options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];
NSArray *features = [detector featuresInImage:ciimage];
if (features.count) {
for (CIFeature *feature in features) {
if ([feature isKindOfClass:[CIQRCodeFeatureclass]]) {
content = ((CIQRCodeFeature *)feature).messageString;
break;
}
}
} else {
[selfaddAlertViewControllerWithMessage:@"未正常解析二维码图片, 请确保iphone5/5c以上的设备"];
NSLog(@"未正常解析二维码图片, 请确保iphone5/5c以上的设备");
}
return content;
}
#pragma mark - 提示框
- (void)addAlertViewControllerWithMessage:(NSString *)message
{
UIAlertController *alert = [UIAlertControlleralertControllerWithTitle:@"解析内容" message:[message stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertActionactionWithTitle:@"朕知道了!"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction * _Nonnull action) {
[self.codeCaptureSessionstartRunning];
[selfaddAnimationForLine]; // 上下进行扫描的线动画
}]];
[selfpresentViewController:alert animated:YEScompletion:nil];
}
#pragma mark - 二维码采集对象
- (AVCaptureSession *)codeCaptureSession
{
if (!_codeCaptureSession) {
// 二维码采集对象
_codeCaptureSession = [[AVCaptureSessionalloc] init];
}
return_codeCaptureSession;
}
#pragma mark - 显示采集图像的对象
- (AVCaptureVideoPreviewLayer *)codeCaptureVideoPreviewLayer
{
if (!_codeCaptureVideoPreviewLayer) {
_codeCaptureVideoPreviewLayer = [AVCaptureVideoPreviewLayerlayerWithSession:self.codeCaptureSession];
_codeCaptureVideoPreviewLayer.bounds = self.view.bounds;
_codeCaptureVideoPreviewLayer.position = self.view.center;
[self.view.layerinsertSublayer:_codeCaptureVideoPreviewLayeratIndex:0];
}
return_codeCaptureVideoPreviewLayer;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
#if TARGET_IPHONE_SIMULATOR//模拟器
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"小提示" message:@"模拟器不能进行扫码" delegate:nil cancelButtonTitle:@"朕知道了!" otherButtonTitles:nil,nil];
[alert show];
#elif TARGET_OS_IPHONE//真机
NSLog(@"真机运行时");
#endif
}
#pragma mark - viewDidLoad
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view.
// 隐藏返回按钮的文字
[[UIBarButtonItemappearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60)
forBarMetrics:UIBarMetricsDefault];
//------------------------------------------------------ 创建输入流--------------------------------------------------------
// 信息采集设备
AVCaptureDevice *codeCaptureDevice = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error;
AVCaptureDeviceInput *input = [AVCaptureDeviceInputdeviceInputWithDevice:codeCaptureDevice error:&error];
if (error) {
NSLog(@"创建输入流error:%@",error);
return;
}
// 设置输入流
[self.codeCaptureSessionaddInput:input];
//------------------------------------------------------ 创建输入流--------------------------------------------------
//------------------------------------------------------ 创建输出流--------------------------------------------------
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutputalloc] init];
// 设置输出流
[self.codeCaptureSessionaddOutput:output];
//设置输出流代理,在代理中获取二维码的结果
[output setMetadataObjectsDelegate:selfqueue:dispatch_get_main_queue()];
// 设置输出类型
output.metadataObjectTypes = @[AVMetadataObjectTypeUPCECode,
AVMetadataObjectTypeCode39Code,
AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeEAN13Code,
AVMetadataObjectTypeEAN8Code,
AVMetadataObjectTypeCode93Code,
AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypePDF417Code,
AVMetadataObjectTypeQRCode,
AVMetadataObjectTypeAztecCode,
AVMetadataObjectTypeInterleaved2of5Code,
AVMetadataObjectTypeITF14Code,
AVMetadataObjectTypeDataMatrixCode];
// [output availableMetadataObjectTypes]; 获取输出支持类型
//设置采样率,越高识别越精准,速度越慢
[self.codeCaptureSessionsetSessionPreset:AVCaptureSessionPreset1920x1080];
//------------------------------------------------------ 创建输出流--------------------------------------------------
// 采集图像显示
[selfcodeCaptureVideoPreviewLayer];
// 开始采集
[self.codeCaptureSessionstartRunning];
}
#pragma mark - 输出流代理方法----采集到数据就会调用该方法
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
// 获得二维码数据
AVMetadataMachineReadableCodeObject *codeObject = [metadataObjects lastObject];
//转化为字符串
NSString *resultString = codeObject.stringValue;
if (resultString) {
[self.codeCaptureSessionstopRunning]; // 停止采集二维码
self.topLayoutConstraint.constant = 10;
[self.codeCaptureVideoPreviewLayerremoveFromSuperlayer];// 删除预览图层
}
[selfaddAlertViewControllerWithMessage:resultString];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[selfaddAnimationForLine]; // 上下进行扫描的线动画
}
#pragma mark - 上下进行扫描的线动画
- (void)addAnimationForLine
{
self.topLayoutConstraint.constant = 10;
[self.viewlayoutIfNeeded];
[UIViewbeginAnimations:@"LineAnimation"context:nil];
[UIViewsetAnimationDuration:1.0f];
[UIViewsetAnimationRepeatAutoreverses:YES];
[UIViewsetAnimationRepeatCount:INFINITY];
[UIViewsetAnimationCurve:UIViewAnimationCurveEaseInOut];
self.topLayoutConstraint.constant = [UIScreenmainScreen].bounds.size.width-40-40;
[self.viewlayoutIfNeeded];
[UIViewcommitAnimations];
}
======================二维码扫描和解析=============================
======================二维码生成=============================
#pragma mark - viewDidLoad
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view.
[[UIBarButtonItemappearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60)
forBarMetrics:UIBarMetricsDefault];
self.codeImageView.image = [selfimageBlackToTransparent: [selfcreateNoninterpolatedUIImageFormCIImage:[selfcreateQRForString:@"请输入要生成二维码的内容"] withSize:CGRectGetWidth(self.codeImageView.frame)] withRed:0.fandGreen:0.fandBlue:0.f];
self.codeImageView.layer.shadowOffset = CGSizeMake(0, 0.5); // 设置阴影的偏移量
self.codeImageView.layer.shadowRadius = 1; // 设置阴影的半径
self.codeImageView.layer.shadowColor = [UIColorblackColor].CGColor; // 设置阴影的颜色为黑色
self.codeImageView.layer.shadowOpacity = 0.3; // 设置阴影的不透明度
}
#pragma mark - 根据指定的字符串来生成二维码的CIImage对象
- (CIImage *)createQRForString:(NSString *)QRString
{
// 获取支持的二维码和条码生成器
NSLog(@"%@",[CIFilterfilterNamesInCategory:kCICategoryGenerator]);
// 实例化二维码滤镜
CIFilter *QRFilter = [CIFilterfilterWithName:@"CIQRCodeGenerator"];
// 恢复滤镜的默认属性
[QRFilter setDefaults]; // 可以省略
// 设置二维码的内容
[QRFilter setValue:[QRString dataUsingEncoding:NSUTF8StringEncoding] forKey:@"inputMessage"];
// 设置二维码的纠错级别
[QRFilter setValue:@"M"forKey:@"inputCorrectionLevel"];
return QRFilter.outputImage;
}
#pragma mark - 根据指定的CIImage对象来转换成指定大小的UIImage对象
- (UIImage *)createNoninterpolatedUIImageFormCIImage:(CIImage *)image
withSize:(CGFloat)size
{
CGRect extent = CGRectIntegral(image.extent);
CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
// 创建bitmap
size_t with = CGRectGetWidth(extent)*scale;
size_t height = CGRectGetHeight(extent)*scale;
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
CGContextRef bitmap = CGBitmapContextCreate(nil, with, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
CIContext *context = [CIContextcontextWithOptions:nil];
CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
CGContextSetInterpolationQuality(bitmap, kCGInterpolationNone);
CGContextScaleCTM(bitmap, scale, scale);
CGContextDrawImage(bitmap, extent, bitmapImage);
// 保存bitmap到图片
CGImageRef scaledImage = CGBitmapContextCreateImage(bitmap);
CGContextRelease(bitmap);
CGImageRelease(bitmapImage);
return [UIImageimageWithCGImage:scaledImage];
}
#pragma mark - 二维码颜色填充
void ProviderReleaseData (void *info, const void *data, size_t size){
free((void*)data);
}
- (UIImage*)imageBlackToTransparent:(UIImage*)image withRed:(CGFloat)red andGreen:(CGFloat)green andBlue:(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
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, ProviderReleaseData);
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 - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifierisEqualToString:@"GenerateVCToQRCodeSetVC"]) {
QRCodeSetViewController *QRCodeSetVC = segue.destinationViewController;
[QRCodeSetVC setQRCodeSetBlock:^(CGFloat R, CGFloat G , CGFloat B, NSString *QRCodeContent) {
self.codeImageView.image = [selfimageBlackToTransparent: [selfcreateNoninterpolatedUIImageFormCIImage:[selfcreateQRForString:QRCodeContent] withSize:CGRectGetWidth(self.codeImageView.frame)] withRed:R andGreen:G andBlue:B];
}];
}
}