iOS 系统原生二维码

本文中使用的是系统原生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];

}];

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容