本文中使用的是系統(tǒng)原生coreimage抚官,實(shí)現(xiàn)功能?二維碼掃描和解析和生成
======================二維碼掃描和解析=============================
@interfaceScanViewController ()?
@property (weak, nonatomic) IBOutletNSLayoutConstraint *topLayoutConstraint;
@property (nonatomic,strong) AVCaptureSession *codeCaptureSession;
@property (nonatomic,strong) AVCaptureVideoPreviewLayer *codeCaptureVideoPreviewLayer;@end
@implementation ScanViewController
#pragma mark - 進(jìn)入相冊- (IBAction)QRCodeFromPickeC:(id)sender {? ? ? ??
UIImagePickerController *imagePC = [[UIImagePickerControlleralloc] init];? ? ? ?
?imagePC.delegate = self;? ? ? ?
?[selfpresentViewController:imagePC animated:YEScompletion:nil];? ? }
#pragma mark - 點(diǎn)擊圖片進(jìn)行解析- (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以上的設(shè)備"];
NSLog(@"未正常解析二維碼圖片, 請確保iphone5/5c以上的設(shè)備");
}
return content;
}
#pragma mark - 提示框
- (void)addAlertViewControllerWithMessage:(NSString *)message
{
UIAlertController *alert = [UIAlertControlleralertControllerWithTitle:@"解析內(nèi)容"? message:[message stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertActionactionWithTitle:@"朕知道了扬跋!"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction * _Nonnull action) {
[self.codeCaptureSessionstartRunning];
[selfaddAnimationForLine]; // 上下進(jìn)行掃描的線動畫
}]];
[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:@"模擬器不能進(jìn)行掃碼" delegate:nil cancelButtonTitle:@"朕知道了!" otherButtonTitles:nil,nil];
[alert show];
#elif TARGET_OS_IPHONE//真機(jī)
NSLog(@"真機(jī)運(yùn)行時(shí)");
#endif
}
#pragma mark - viewDidLoad
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view.
// 隱藏返回按鈕的文字
[[UIBarButtonItemappearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60)
forBarMetrics:UIBarMetricsDefault];
//------------------------------------------------------ 創(chuàng)建輸入流--------------------------------------------------------
// 信息采集設(shè)備
AVCaptureDevice *codeCaptureDevice = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error;
AVCaptureDeviceInput *input = [AVCaptureDeviceInputdeviceInputWithDevice:codeCaptureDevice error:&error];
if (error) {
NSLog(@"創(chuàng)建輸入流error:%@",error);
return;
}
// 設(shè)置輸入流
[self.codeCaptureSessionaddInput:input];
//------------------------------------------------------ 創(chuàng)建輸入流--------------------------------------------------
//------------------------------------------------------ 創(chuàng)建輸出流--------------------------------------------------
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutputalloc] init];
// 設(shè)置輸出流
[self.codeCaptureSessionaddOutput:output];
//設(shè)置輸出流代理凌节,在代理中獲取二維碼的結(jié)果
[output setMetadataObjectsDelegate:selfqueue:dispatch_get_main_queue()];
// 設(shè)置輸出類型
output.metadataObjectTypes = @[AVMetadataObjectTypeUPCECode,
AVMetadataObjectTypeCode39Code,
AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeEAN13Code,
AVMetadataObjectTypeEAN8Code,
AVMetadataObjectTypeCode93Code,
AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypePDF417Code,
AVMetadataObjectTypeQRCode,
AVMetadataObjectTypeAztecCode,
AVMetadataObjectTypeInterleaved2of5Code,
AVMetadataObjectTypeITF14Code,
AVMetadataObjectTypeDataMatrixCode];
//? ? [output availableMetadataObjectTypes]; 獲取輸出支持類型
//設(shè)置采樣率钦听,越高識別越精準(zhǔn)洒试,速度越慢
[self.codeCaptureSessionsetSessionPreset:AVCaptureSessionPreset1920x1080];
//------------------------------------------------------ 創(chuàng)建輸出流--------------------------------------------------
// 采集圖像顯示
[selfcodeCaptureVideoPreviewLayer];
// 開始采集
[self.codeCaptureSessionstartRunning];
}
#pragma mark - 輸出流代理方法----采集到數(shù)據(jù)就會調(diào)用該方法
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
// 獲得二維碼數(shù)據(jù)
AVMetadataMachineReadableCodeObject *codeObject = [metadataObjects lastObject];
//轉(zhuǎn)化為字符串
NSString *resultString = codeObject.stringValue;
if (resultString) {
[self.codeCaptureSessionstopRunning]; // 停止采集二維碼
self.topLayoutConstraint.constant = 10;
[self.codeCaptureVideoPreviewLayerremoveFromSuperlayer];// 刪除預(yù)覽圖層
}
[selfaddAlertViewControllerWithMessage:resultString];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[selfaddAnimationForLine]; // 上下進(jìn)行掃描的線動畫
}
#pragma mark - 上下進(jìn)行掃描的線動畫
- (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:@"請輸入要生成二維碼的內(nèi)容"] withSize:CGRectGetWidth(self.codeImageView.frame)] withRed:0.fandGreen:0.fandBlue:0.f];
self.codeImageView.layer.shadowOffset = CGSizeMake(0, 0.5);? // 設(shè)置陰影的偏移量
self.codeImageView.layer.shadowRadius = 1;? // 設(shè)置陰影的半徑
self.codeImageView.layer.shadowColor = [UIColorblackColor].CGColor; // 設(shè)置陰影的顏色為黑色
self.codeImageView.layer.shadowOpacity = 0.3; // 設(shè)置陰影的不透明度
}
#pragma mark - 根據(jù)指定的字符串來生成二維碼的CIImage對象
- (CIImage *)createQRForString:(NSString *)QRString
{
// 獲取支持的二維碼和條碼生成器
NSLog(@"%@",[CIFilterfilterNamesInCategory:kCICategoryGenerator]);
// 實(shí)例化二維碼濾鏡
CIFilter *QRFilter = [CIFilterfilterWithName:@"CIQRCodeGenerator"];
// 恢復(fù)濾鏡的默認(rèn)屬性
[QRFilter setDefaults]; // 可以省略
// 設(shè)置二維碼的內(nèi)容
[QRFilter setValue:[QRString dataUsingEncoding:NSUTF8StringEncoding] forKey:@"inputMessage"];
// 設(shè)置二維碼的糾錯級別
[QRFilter setValue:@"M"forKey:@"inputCorrectionLevel"];
return QRFilter.outputImage;
}
#pragma mark - 根據(jù)指定的CIImage對象來轉(zhuǎn)換成指定大小的UIImage對象
- (UIImage *)createNoninterpolatedUIImageFormCIImage:(CIImage *)image
withSize:(CGFloat)size
{
CGRect extent = CGRectIntegral(image.extent);
CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
// 創(chuàng)建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)? ? // 將白色變成透明
{
// 改成下面的代碼,會將圖片轉(zhuǎn)成想要的顏色
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];
}];
}
}