今天博主有一個二維碼掃描和生成的需求,遇到了一些困難點,在此和大家分享,希望能夠共同進步.
從iOS7開始官方集成了二維碼的掃描和生成功能
此前被廣泛使用的zbarsdk目前不支持64位處理器
1.掃描二維碼
掃描二維碼需要導入AVFoundation框架
利用攝像頭識別二維碼中的內容(模擬器不行)
輸入(攝像頭)
由會話將攝像頭採集到的二維碼圖像轉換成字符串數據
輸出(數據)
由預覽圖層顯示掃描場景
// 實例化拍攝設備
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 設置輸入設備
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
// 設置元數據輸出
// 實例化拍攝元數據輸出
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
// 設置輸出數據代理
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 添加拍攝會話
// 實例化拍攝會話
AVCapturesession *session = [[AVCaptureSession alloc] init];
// 添加會話輸入
[session addInput:input];
// 添加會話輸出
[session addOutput:output];
// 設置輸出數據類型,需要將元數據輸出添加到會話後,才能指定元數據類型,否則會報錯
[output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
// 視頻預覽圖層
// 實例化預覽圖層
AVCaptureVideoPReviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:_session];
preview.videoGravity = AVLayerVideoGravityResizeaspectFill;
preview.frame = self.view.bounds;
// 將圖層插入當前視圖
[self.view.layer insertSublayer:preview atIndex:100];
self.previewLayer = preview;
// 啓動會話
[_session startRunning];
2.掃描二維碼實例
@interface ViewController ()<AVCaptureMetadataOutputObjectsDelegate>
@property (nonatomic, strong) AVCaptureSession *session;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 1. 實例化拍攝設備
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 2. 設置輸入設備
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
// 3. 設置元數據輸出
// 3.1 實例化拍攝元數據輸出
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
// 3.3 設置輸出數據代理
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 4. 添加拍攝會話
// 4.1 實例化拍攝會話
AVCaptureSession *session = [[AVCaptureSession alloc] init];
// 4.2 添加會話輸入
[session addInput:input];
// 4.3 添加會話輸出
[session addOutput:output];
// 4.3 設置輸出數據類型,需要將元數據輸出添加到會話後,才能指定元數據類型,否則會報錯
[output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
self.session = session;
// 5. 視頻預覽圖層
// 5.1 實例化預覽圖層, 傳遞_session是爲了告訴圖層將來顯示什麼內容
AVCaptureVideoPreviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:_session];
preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
preview.frame = self.view.bounds;
// 5.2 將圖層插入當前視圖
[self.view.layer insertSublayer:preview atIndex:100];
self.previewLayer = preview;
// 6. 啓動會話
[_session startRunning];
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
// 會頻繁的掃描,調用代理方法
// 1. 如果掃描完成,停止會話
[self.session stopRunning];
// 2. 刪除預覽圖層
[self.previewLayer removeFromSuperlayer];
NSLog(@"%@", metadataObjects);
// 3. 設置界面顯示掃描結果
if (metadataObjects.count > 0)
{
AVMetadataMachineReadableCodeObject *obj = metadataObjects[0];
// 提示:如果需要對url或者名片等信息進行掃描,可以在此進行擴展!
NSLog(@"%@", obj.stringValue);
}
}
@end
3.二維碼的生成
生成二維碼的步驟:
導入CoreImage框架
通過濾鏡CIFilter生成二維碼
二維碼的內容(傳統的條形碼只能放數字):純文本,
名片,
URL
// 1. 實例化二維碼濾鏡
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
// 2. 恢復濾鏡的默認屬性
[filter setDefaults];
// 3. 將字符串轉換成
NSData NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
// 4. 通過KVO設置濾鏡inputMessage數據
[filter setValue:data forKey:@"inputMessage"];
// 5. 獲得濾鏡輸出的圖像
CIImage *outputImage = [filter outputImage];
// 6. 將CIImage轉換成UIImage,並放大顯示
return [UIImage imageWithCIImage:outputImage scale:20.0 orientation:UIImageOrientationUp];
4.生成二維碼實例
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.imgView=[[UIImageView alloc]initWithFrame:CGRectMake(100, 100, [UIScreen mainScreen].bounds.size.width/2.0, [UIScreen mainScreen].bounds.size.width/2.0)];
[self.view addSubview:_imgView];
[self erweima];
}
-(void)erweima
{
//二維碼濾鏡
CIFilter *filter=[CIFilter filterWithName:@"CIQRCodeGenerator"];
//恢復濾鏡的默認屬性
[filter setDefaults];
//將字符串轉換成NSData
NSData *data=[@"www.baidu.com" dataUsingEncoding:NSUTF8StringEncoding];
//通過KVO設置濾鏡inputmessage數據
[filter setValue:data forKey:@"inputMessage"];
//獲得濾鏡輸出的圖像
CIImage *outputImage=[filter outputImage];
//將CIImage轉換成UIImage,並放大顯示
_imgView.image=[self createNonInterpolatedUIImageFormCIImage:outputImage withSize:100.0];
//如果還想加上陰影,就在ImageView的Layer上使用下面代碼添加陰影
_imgView.layer.shadowOffset=CGSizeMake(0, 0.5);//設置陰影的偏移量
_imgView.layer.shadowRadius=1;//設置陰影的半徑
_imgView.layer.shadowColor=[UIColor blackColor].CGColor;//設置陰影的顏色爲黑色
_imgView.layer.shadowOpacity=0.3;
}
//改變二維碼大小
- (UIImage *)createNonInterpolatedUIImageFormCIImage:(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];
}