iOS開(kāi)發(fā)_原生二維碼生成與讀取

今天有時(shí)間整理下原生的二維碼的生成與讀取。

準(zhǔn)備工作

  • 導(dǎo)入<CoreImage/CoreImage.h>,生成二維碼用
  • 導(dǎo)入<AVFoundation/AVFoundation.h>,讀取二維碼用
  • 協(xié)議AVCaptureMetadataOutputObjectsDelegate,這是有關(guān)攝像設(shè)備輸出的相關(guān)代理
  • 注意:掃描二維碼的時(shí)候,要在info.plist文件中添加字段,否則會(huì)崩潰(iOS10之后的隱私權(quán)限問(wèn)題)

    <key>NSPhotoLibraryUsageDescription</key>
    <string>App需要您的同意,才能訪問(wèn)相冊(cè)</string>

    <key>NSCameraUsageDescription</key>
    <string>App需要您的同意,才能訪問(wèn)相機(jī)</string>

二維碼的生成

1.生成二維碼的步驟:

1)導(dǎo)入CoreImage框架
2)通過(guò)濾鏡CIFilter生成二維碼
代碼如下
調(diào)用下方根據(jù)字符串生成二維碼的方法即可獲得二維碼
 // 生成二維碼
- (UIImage *)createImageWithString:(NSString *)string{

// 1.實(shí)例化二維碼濾鏡
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
// 2.恢復(fù)濾鏡的默認(rèn)屬性(因?yàn)闉V鏡可能保存上一次的屬性)
[filter setDefaults];

// 3.講字符串轉(zhuǎn)換為NSData
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];*

// 4.通過(guò)KVO設(shè)置濾鏡inputMessage數(shù)據(jù)
[filter setValue:data forKey:@"inputMessage"];

// 5.通過(guò)了濾鏡輸出的圖像
CIImage *outputImage = [filter outputImage];

// 6.因?yàn)樯傻亩S碼模糊,所以通過(guò)createNonInterpolatedUIImageFormCIImage:outputImage來(lái)獲得高清的二維碼圖片

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];
}
運(yùn)行結(jié)果

[圖片上傳失敗...(image-bbce1-1542166399362)]


????????????我是可愛(ài)的分割線????????????


二維碼的生成還是比較簡(jiǎn)單的,下面讓我們來(lái)看下二維碼的掃描


????????????我是可愛(ài)的分割線????????????


二維碼的讀取

1.讀取二維碼的步驟:

1)讀取二維碼需要導(dǎo)入AVFoundation框架(上方準(zhǔn)備工作的時(shí)候已經(jīng)說(shuō)了)
2)利用相機(jī)識(shí)別二維碼中的內(nèi)容(只能是真機(jī))
3)會(huì)話將相機(jī)采集到的二維碼圖像轉(zhuǎn)換成字符串?dāng)?shù)據(jù)

2.原生掃描中用到的幾個(gè)類

AVCaptureDevice                        // 拍攝設(shè)備
AVCaptureDeviceInput                   // 輸入設(shè)備
AVCaptureMetadataOutput                // 元數(shù)據(jù)輸出
AVCaptureSession                       // 拍攝會(huì)話
AVCaptureVideoPreviewLayer             // 視頻預(yù)覽圖層
代碼如下
- (void)readQRCode{

// 1.實(shí)例化拍攝裝備
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.添加拍攝會(huì)話
self.session = [[AVCaptureSession alloc] init];
[self.session addInput:input];       // 添加會(huì)話輸入
[self.session addOutput:output];     // 添加會(huì)話輸出

[output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];      // 設(shè)置輸出數(shù)據(jù)類型(需要將元數(shù)據(jù)輸出添加到會(huì)話后才能制定元數(shù)據(jù)類型,否則會(huì)報(bào)錯(cuò))

// 5.視頻預(yù)覽圖層
self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session]; // 傳遞session是為了告訴圖層將來(lái)顯示什么內(nèi)容
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;   // 顯示方式
// 設(shè)置videoGravity,顧名思義就是視頻播放時(shí)的拉伸方式,默認(rèn)是AVLayerVideoGravityResizeAspect
// AVLayerVideoGravityResizeAspect 保持視頻的寬高比并使播放內(nèi)容自動(dòng)適應(yīng)播放窗口的大小。
// AVLayerVideoGravityResizeAspectFill 和前者類似,但它是以播放內(nèi)容填充而不是適應(yīng)播放窗口的大小。最后一個(gè)值會(huì)拉伸播放內(nèi)容以適應(yīng)播放窗口.
// 因?yàn)榭紤]到全屏顯示以及設(shè)備自適應(yīng),這里我們采用fill填充

self.previewLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:self.previewLayer atIndex:0]; // 將圖層插入當(dāng)前圖層

// 6.啟動(dòng)會(huì)話
[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ù),則停止會(huì)話
    [self.session stopRunning];
    // 3.刪除預(yù)覽圖層
    [self.previewLayer removeFromSuperlayer];
    
    AVMetadataMachineReadableCodeObject *metadataObject = metadataObjects[0];
    
    // AVMetadataMachineReadableCodeObject 是AVMetadataObject的具體子類定義的特性檢測(cè)一維或二維條形碼。
    // AVMetadataMachineReadableCodeObject代表一個(gè)單一的照片中發(fā)現(xiàn)機(jī)器可讀的代碼。這是一個(gè)不可變對(duì)象描述條碼的特性和載荷。
    // 在支持的平臺(tái)上,AVCaptureMetadataOutput輸出檢測(cè)機(jī)器可讀的代碼對(duì)象的數(shù)組
    
    NSString *stringValue = metadataObject.stringValue;
    
    if ([stringValue containsString:@"http"]) {
        
        // 如果是字符串,則打開(kāi)連接
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:stringValue] options:[NSDictionary dictionary] completionHandler:^(BOOL success) {
            
            if (success) {
                NSLog(@"成功");
            }
        }];
    }else{
        NSLog(@"普通字符串:%@",stringValue);     // 可以將字符串放到需要用到的地方(比如label)
     }
   }
 }

小結(jié)

代碼已經(jīng)上傳至git:
--> 傳送門:https://github.com/272095249/CreateAndReadQRCode.git

有問(wèn)題歡迎指正以及相互探討 —— CoderSun

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容