二维码可以很方便的分享一些信息而广泛使用,很多app也就有了生成二维码和扫瞄二维码的需求了,所以用到的地方不少, 再正常不过的一个功能了,早期开发的时候可能使用过ZBar或者ZXing这两个相对古老的第三方,在苹果没有开发原生二维码扫描和生成的时候,这两个第三方也给我们带来了很多方便,对于现在这两个使用的频率也不高了,因为苹果原生的意见有很高的效率了。
效果实现
二维码的生成
- 不带Logo图标的二维码
-> 导入 #import "JYErWeiCode.h" 头文件
JYErWeiCode *erWeiCode = [[JYErWeiCode alloc] init];
erWeiCode.source = @"http://www.jianshu.com/p/47bcb0422c4a"; // 设置二维码存储的资源信息
//erWeiCode.erWeiCodeColor = setColor(56, 34, 230); // 设置二维码的颜色,默认是黑白
self.imgView.image = [erWeiCode erWeiCode]; // 生成一张高清的二维码图片,显示出来
默认生成二维码黑白颜色.png
erWeiCode.marginColor = [UIColor cyanColor]; // 自定义设置二维码的颜色
自定义二维码颜色效果.png
- 带Logo图标的二维码(基本上带有logo图片都会设置圆角)
JYErWeiCode *erWeiCode = [[JYErWeiCode alloc] init];
erWeiCode.source = @"http://www.jianshu.com/p/47bcb0422c4a";
erWeiCode.logo = @"IMG_6396"; // logo图片资源
erWeiCode.rounde = 20.0f; // 图片圆角大小
erWeiCode.margin = 4.0f; // 外边框的宽度
erWeiCode.erWeiCodeColor = [UIColor cyanColor];
erWeiCode.marginColor = [UIColor cyanColor]; // 外边框的颜色
self.imgView.image = [erWeiCode erWeiCode];
带logo图标的二维码.png
!注意:在自定义的时候logo图片的大小不能过大,过大会遮住一下二维码的扫描位置从而影响二维码的扫描
二维码的扫描
-> 在控制器导入#import "JYScanErWeiCode.h" 、#import "JYPreviewView.h"
1.创建一个相机捕获会话的view
- (JYPreviewView *)previewView
{
if (!_previewView) {
_previewView = [[JYPreviewView alloc] init];
_previewView.cornerColor = [UIColor cyanColor]; // 设置四个角边框的颜色
[self.view addSubview:_previewView];
}
return _previewView;
}
2.加载二维码扫描
// 懒加载二维码扫描
- (JYScanErWeiCode *)scanErWeiCode
{
if (!_scanErWeiCode) {
_scanErWeiCode = [[JYScanErWeiCode alloc] initWithPreviewView:self.previewView];
_scanErWeiCode.delegate = self;
}
return _scanErWeiCode;
}
3.开启相机扫描
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.scanErWeiCode startSession];
}
4.当控制器消耗时关闭相机
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.scanErWeiCode stopSession];
}
5.设置JYScanErWeiCodeDelegate的代理方法
- (void)erWeiCodeScanStringValue:(NSString *)str
{
NSLog(@"扫描结果:%@", str);
JYWebController *webCtl = [[JYWebController alloc] init];
webCtl.urlStr = str;
[self.navigationController pushViewController:webCtl animated:YES];
}
效果展示
GIF.gif具体代码实现
-> source 在创建生成二维码的对象时,一定要有值
- (UIImage *)erWeiCode
{
if (self.source) {
// 1.生成清晰的二维码图片
UIImage *imgQRCode = [self createQRCodeImage:self.source];
// 2.设置二维码的颜色 (默认是黑色)
imgQRCode = [JYErWeiCode specialColorImage:imgQRCode color:self.erWeiCodeColor];
// 3.生成一张有圆角外边框的logo图片
UIImage *logoImg = [self createRoundeLogo];
if (logoImg) { // 如果需要设置logo图片
// 4.合成一张有logo图标的二维码
UIImage *needImg = [self addIconToQRCodeImage:imgQRCode icon:logoImg];
return needImg;
} else // 不需要设置logo图片
{
return imgQRCode;
}
} else
{
NSLog(@"Error: source= nil,你创建了一个空的二维码,请设置二维码的内容");
return nil;
}
}
- (UIImage *)createRoundeLogo
{
if (self.logo.length) {
if (self.rounde > 0) {
// 1.生成一张圆角logo图片
UIImage *logoImg = [self imageRoundeImage:[UIImage imageNamed:self.logo] rounde:self.rounde];
if (self.margin > 0) {
// 2.生成一张有外边框的logo图片 (默认外边框颜色为白色)
UIColor *marginColor = (self.marginColor == NULL) ? [UIColor whiteColor] : self.marginColor;
UIImage *marginImg = [self imageAddColorBorder:logoImg color:marginColor margin:self.margin];
// 3.设置有外边框logo图片的圆角
UIImage *mLogo = [self imageRoundeImage:marginImg rounde:self.rounde];
return mLogo;
} else {
return logoImg;
}
} else {
return [UIImage imageNamed:self.logo];
}
} else {
return nil;
}
}
对图片处理的操作
描述:使用iOS 7后的CIFilter对象操作,生成二维码图片imgQRCode(会拉伸图片,比较模糊,效果不佳, 使用核心绘图框架CG(Core Graphics)对象操作,进一步针对大小生成二维码图片imgAdaptiveQRCode(图片大小适合,清晰,效果好)
source: 二维码中的数据可以是字符串和URL两种类型, 如果我们想要生成URL的二维码, 只需要把字符串替换为一个URL字符串即可
rate: 越大,越清晰(未提供接口,默认50.0, 如果需要更高清的, 可修改这个值)
- (UIImage *)createQRCodeImage:(NSString *)source
{
// 1. 给滤镜添加数据
NSData *data = [source dataUsingEncoding:NSUTF8StringEncoding];
// 2. 创建一个二维码滤镜实例(CIFilter)
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
[filter setValue:data forKey:@"inputMessage"];
[filter setValue:@"H" forKey:@"inputCorrectionLevel"];
// 3.生成一张清晰度不高的二维码
UIImage *image = [UIImage imageWithCIImage:filter.outputImage
scale:1.0
orientation:UIImageOrientationUp];
// 4.对图片做处理, 使图片大小合适,清晰,效果好
CGFloat width = image.size.width * 50.0;
CGFloat height = image.size.height * 50.0;
UIGraphicsBeginImageContext(CGSizeMake(width, height));
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
[image drawInRect:CGRectMake(0, 0, width, height)];
UIImage *needImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return needImg;
}
默认产生的黑白色的二维码图片;我们可以让它产生其它颜色的二维码图片,例如:蓝白色的二维码图片
color: 设置二维码的颜色
+ (UIImage *)specialColorImage:(UIImage *)image color:(UIColor *)color
{
CGFloat components[3];
[JYErWeiCode getRGBComponents:components forColor:color];
const CGFloat imageW = image.size.width;
const CGFloat imageH = image.size.height;
size_t bytesPerRow = imageW * 4;
uint32_t *rgbImageBuf = (uint32_t *)malloc(bytesPerRow *imageH);
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGContextRef contextRef = CGBitmapContextCreate(rgbImageBuf, imageW, imageH, 8, bytesPerRow, colorSpaceRef, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
CGContextDrawImage(contextRef, CGRectMake(0, 0, imageW, imageH), image.CGImage);
CGFloat pixelNum = imageW * imageH;
uint32_t *pCurPtr = rgbImageBuf;
for (int i = 0; i < pixelNum; i ++, pCurPtr ++) {
if ((*pCurPtr & 0xFFFFFF00) < 0x99999900) {
uint8_t *ptr = (uint8_t *)pCurPtr;
ptr[3] = components[0];
ptr[2] = components[1];
ptr[1] = components[2];
} else {
uint8_t *ptr = (uint8_t *)pCurPtr;
ptr[0] = 0;
}
}
CGDataProviderRef dataProviderRef = CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageH, preoviderReleaseData);
CGImageRef imageRef = CGImageCreate(imageW, imageH, 8, 32, bytesPerRow, colorSpaceRef, kCGImageAlphaLast | kCGBitmapByteOrder32Little, dataProviderRef, NULL, true, kCGRenderingIntentDefault);
CGDataProviderRelease(dataProviderRef);
UIImage *img = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGContextRelease(contextRef);
CGColorSpaceRelease(colorSpaceRef);
return img;
}
设置图片的圆角
rounde: 设置圆角大小
注明:在这设置的图片在圆角周围有羽化的现象,不知道啥情况,有大神知道可留言一下,谢谢
- (UIImage *)imageRoundeImage:(UIImage *)image rounde:(CGFloat)rounde
{
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
UIGraphicsBeginImageContextWithOptions(image.size, NO, 1.0);
[UIBezierPath bezierPathWithRect:rect];
[[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, image.size.width, image.size.height) cornerRadius:rounde] addClip];
[image drawInRect:rect];
UIImage *needImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return needImg;
}
给图片添加不同颜色的边框
color: 外边框颜色
margin: 外边框大小
- (UIImage *)imageAddColorBorder:(UIImage *)image color:(UIColor *)color margin:(CGFloat)margin
{
CGFloat imageW = image.size.width;
CGFloat imageH = image.size.height;
CGFloat colorW = imageW + margin * 2;
CGFloat colorH = imageH + margin * 2;
// 用颜色来转换成一张图片
UIImage *colorImg = [JYErWeiCode imageWithColor:color size:CGSizeMake(colorW, colorH)];
UIGraphicsBeginImageContext(colorImg.size);
[colorImg drawInRect:CGRectMake(0, 0, colorW, colorH)];
[image drawInRect:CGRectMake(margin, margin, imageW, imageH)];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
两张图片合成一张
image: 二维码
icon: 中间Logo图标
- (UIImage *)addIconToQRCodeImage:(UIImage *)image icon:(UIImage *)icon
{
UIGraphicsBeginImageContext(image.size);
CGFloat imageW = image.size.width;
CGFloat imageH = image.size.height;
CGFloat iconW = imageW * 0.25;
CGFloat iconH = imageH * 0.25;
[image drawInRect:CGRectMake(0, 0, imageW, imageH)];
[icon drawInRect:CGRectMake((imageW - iconW) * 0.5, (imageH - iconH) * 0.5, iconW, iconH)];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
扫描代码实现
- 初始化相机会话 (一开始最好判断有没有相机权限,没有的话跳转到设置中设置允许使用相机,当前没有做着个处理)
- (void)initSession
{
self.captureSession = [[AVCaptureSession alloc] init];
// Setup the preview view.
self.previewView.session = self.captureSession;
// 与此队列中的会话和其他会话对象进行通信
self.sessionQueue = dispatch_queue_create( "session queue", DISPATCH_QUEUE_SERIAL );
// 设置捕追会话
// 一般来说是不安全的 AVCaptureSession 突变 或 其任何输入,输出,或连接多个线程,在同一时间
dispatch_async( self.sessionQueue, ^{
NSError *error = nil;
AVCaptureDevice *videoDevice = [JYScanErWeiCode deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
if ( ! videoDeviceInput ) {
NSLog( @"Could not create video device input: %@", error );
}
[self.captureSession beginConfiguration];
if ( [self.captureSession canAddInput:videoDeviceInput] ) {
[self.captureSession addInput:videoDeviceInput];
self.deviceInput = videoDeviceInput;
AVCaptureDevice *currentVideoDevice = self.deviceInput.device;
self.captureDevice = currentVideoDevice;
} else
{
// 无法将视频设备输入到会话中
NSLog( @"Could not add video device input to the session" );
}
dispatch_async( dispatch_get_main_queue(), ^{
AVCaptureVideoPreviewLayer *previewLayer = (AVCaptureVideoPreviewLayer *)self.previewView.layer;
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
});
self.metadataOutput = [[AVCaptureMetadataOutput alloc]init];
[self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
if ([self.captureSession canAddOutput:self.metadataOutput]) {
[self.captureSession addOutput:self.metadataOutput];
}
// 条码类型 AVMetadataObjectTypeQRCode
self.metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];
[self.captureSession commitConfiguration];
});
}
- 设置AVCaptureMetadataOutput代理
- AVCaptureMetadataOutputObjectsDelegate获取扫描的信息
#pragma mark AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
NSString *stringValue;
if ([metadataObjects count] >0){
AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];
stringValue = metadataObject.stringValue;
if (self.delegate && [self.delegate respondsToSelector:@selector(erWeiCodeScanStringValue:)]) {
[self.delegate erWeiCodeScanStringValue:stringValue];
}
[self stopSession];
}
}
网友评论