今天有時間整理下原生的二維碼的生成與讀取。
準備工作
- 導入
<CoreImage/CoreImage.h>
干旁,生成二維碼用 - 導入
<AVFoundation/AVFoundation.h>
炮沐,讀取二維碼用 - 協(xié)議
AVCaptureMetadataOutputObjectsDelegate
,這是有關(guān)攝像設(shè)備輸出的相關(guān)代理 -
注意:掃描二維碼的時候换薄,要在info.plist文件中添加字段鲜戒,否則會崩潰(iOS10之后的隱私權(quán)限問題)
<key>NSPhotoLibraryUsageDescription</key>
<string>App需要您的同意,才能訪問相冊</string>
<key>NSCameraUsageDescription</key>
<string>App需要您的同意,才能訪問相機</string>
二維碼的生成
1.生成二維碼的步驟:
1)導入CoreImage框架
2)通過濾鏡CIFilter生成二維碼
代碼如下
調(diào)用下方根據(jù)字符串生成二維碼的方法即可獲得二維碼
// 生成二維碼
- (UIImage *)createImageWithString:(NSString *)string{
// 1.實例化二維碼濾鏡
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
// 2.恢復濾鏡的默認屬性(因為濾鏡可能保存上一次的屬性)
[filter setDefaults];
// 3.講字符串轉(zhuǎn)換為NSData
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];*
// 4.通過KVO設(shè)置濾鏡inputMessage數(shù)據(jù)
[filter setValue:data forKey:@"inputMessage"];
// 5.通過了濾鏡輸出的圖像
CIImage *outputImage = [filter outputImage];
// 6.因為生成的二維碼模糊遏餐,所以通過createNonInterpolatedUIImageFormCIImage:outputImage來獲得高清的二維碼圖片
UIImage *image = [self getErWeiMaImageFormCIImage:outputImage withSize:200];
return image;
}
// 獲取高清二維碼圖片
- (UIImage *)getErWeiMaImageFormCIImage:(CIImage *)image withSize:(CGFloat) size {
CGRect extent = CGRectIntegral(image.extent);
CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
// 1.創(chuàng)建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);
// 2.保存bitmap到圖片
CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
CGContextRelease(bitmapRef);
CGImageRelease(bitmapImage);
return [UIImage imageWithCGImage:scaledImage];
}
運行結(jié)果
[圖片上傳失敗...(image-bbce1-1542166399362)]
????????????我是可愛的分割線????????????
二維碼的生成還是比較簡單的失都,下面讓我們來看下二維碼的掃描
????????????我是可愛的分割線????????????
二維碼的讀取
1.讀取二維碼的步驟:
1)讀取二維碼需要導入AVFoundation框架(上方準備工作的時候已經(jīng)說了)
2)利用相機識別二維碼中的內(nèi)容(只能是真機)
3)會話將相機采集到的二維碼圖像轉(zhuǎn)換成字符串數(shù)據(jù)
2.原生掃描中用到的幾個類
AVCaptureDevice // 拍攝設(shè)備
AVCaptureDeviceInput // 輸入設(shè)備
AVCaptureMetadataOutput // 元數(shù)據(jù)輸出
AVCaptureSession // 拍攝會話
AVCaptureVideoPreviewLayer // 視頻預覽圖層
代碼如下
- (void)readQRCode{
// 1.實例化拍攝裝備
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 2.設(shè)置輸入設(shè)備
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
// 3.設(shè)置元數(shù)據(jù)輸出
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; // 設(shè)置代理
// 4.添加拍攝會話
self.session = [[AVCaptureSession alloc] init];
[self.session addInput:input]; // 添加會話輸入
[self.session addOutput:output]; // 添加會話輸出
[output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]]; // 設(shè)置輸出數(shù)據(jù)類型(需要將元數(shù)據(jù)輸出添加到會話后才能制定元數(shù)據(jù)類型,否則會報錯)
// 5.視頻預覽圖層
self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session]; // 傳遞session是為了告訴圖層將來顯示什么內(nèi)容
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; // 顯示方式
// 設(shè)置videoGravity,顧名思義就是視頻播放時的拉伸方式,默認是AVLayerVideoGravityResizeAspect
// AVLayerVideoGravityResizeAspect 保持視頻的寬高比并使播放內(nèi)容自動適應播放窗口的大小咳焚。
// AVLayerVideoGravityResizeAspectFill 和前者類似革半,但它是以播放內(nèi)容填充而不是適應播放窗口的大小。最后一個值會拉伸播放內(nèi)容以適應播放窗口.
// 因為考慮到全屏顯示以及設(shè)備自適應,這里我們采用fill填充
self.previewLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:self.previewLayer atIndex:0]; // 將圖層插入當前圖層
// 6.啟動會話
[self.session startRunning];
}
AVCaptureMetadataOutputObjectsDelegate 的代理方法
/**
掃描結(jié)果處理
@param captureOutput 輸出數(shù)據(jù)源
@param metadataObjects 掃描結(jié)果數(shù)組
@param connection 用于協(xié)調(diào)輸入與輸出之間的數(shù)據(jù)流
*/
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
// 1.判斷掃描結(jié)果的數(shù)據(jù)是否存在
if ([metadataObjects count] > 0) {
// 2.如果存在數(shù)據(jù)延刘,則停止會話
[self.session stopRunning];
// 3.刪除預覽圖層
[self.previewLayer removeFromSuperlayer];
AVMetadataMachineReadableCodeObject *metadataObject = metadataObjects[0];
// AVMetadataMachineReadableCodeObject 是AVMetadataObject的具體子類定義的特性檢測一維或二維條形碼六敬。
// AVMetadataMachineReadableCodeObject代表一個單一的照片中發(fā)現(xiàn)機器可讀的代碼。這是一個不可變對象描述條碼的特性和載荷普泡。
// 在支持的平臺上,AVCaptureMetadataOutput輸出檢測機器可讀的代碼對象的數(shù)組
NSString *stringValue = metadataObject.stringValue;
if ([stringValue containsString:@"http"]) {
// 如果是字符串审编,則打開連接
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:stringValue] options:[NSDictionary dictionary] completionHandler:^(BOOL success) {
if (success) {
NSLog(@"成功");
}
}];
}else{
NSLog(@"普通字符串:%@",stringValue); // 可以將字符串放到需要用到的地方(比如label)
}
}
}