不得不說(shuō)梦碗,二維碼是小日本的一個(gè)偉大發(fā)明,它密度小蓖救、信息容量大洪规、容錯(cuò)能力強(qiáng)、成本低循捺、制作難度低等優(yōu)點(diǎn)斩例,使得二維碼得到廣泛的運(yùn)用,我們可以在二維碼里面存儲(chǔ)各種信息巨柒,如網(wǎng)站鏈接樱拴、移動(dòng)支付,非常方便洋满,用戶只需掃一掃就行,所以我們?cè)絹?lái)越多的移動(dòng)應(yīng)用也將一些信息封裝成二維碼了珍坊。
二維碼其實(shí)就是由很多0牺勾、1組成的數(shù)字矩陣,用某種特定的幾何圖形按一定規(guī)律在平面(二維方向上)分布的黑白相間的圖形記錄數(shù)據(jù)符號(hào)信息阵漏;二維碼能夠在橫向和縱向兩個(gè)方位同時(shí)表達(dá)信息驻民,因此能在很小的面積內(nèi)表達(dá)大量的信息。在iOS當(dāng)中履怯,iOS7以后回还,系統(tǒng)自身集成了二維碼的生成與讀取功能,不需要我們?cè)偌傻谌搅颂局蓿籭OS7以下使用libqrencode庫(kù)來(lái)生成二維碼圖片柠硕。二維碼樣式大概有以下三種:
1、普通形式的二維碼
2、自定義顏色的二維碼
3蝗柔、中間帶logo的二維碼
下面介紹下二維碼生成的詳細(xì)步驟:
一闻葵、普通二維碼
我們可以把生成 二維碼方法封裝到一個(gè)工具類或者UIImage類別當(dāng)中,方便以后調(diào)用癣丧,先擬好方法名:
+ (UIImage *)createQRImageWithContent:(NSString *)content size:(CGSize)size;
首先槽畔,我們需要導(dǎo)入頭文件
#import <CoreImage/CoreImage.h>
然后把封裝的文字content
用UTF-8
轉(zhuǎn)一下,不轉(zhuǎn)的話可能導(dǎo)致崩潰胁编,再實(shí)例化一個(gè)CIFilter對(duì)象厢钧,使用CIFilter濾鏡類生成二維碼,再通過(guò)kvo方式給一個(gè)字符串,生成二維碼嬉橙。
NSData *stringData = [content dataUsingEncoding: NSUTF8StringEncoding];
CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
[qrFilter setValue:stringData forKey:@"inputMessage"];//通過(guò)kvo方式給一個(gè)字符串坏快,生成二維碼
二維碼都有一定的容錯(cuò)能力,就是有部分污損或者破損都沒(méi)有關(guān)系憎夷,照常識(shí)別莽鸿。但是也是有限度的,這根據(jù)生成時(shí)使用的糾錯(cuò)級(jí)別而定拾给,可以有7%~30%左右的損壞祥得,實(shí)際上保守一點(diǎn)更好。官方文檔顯示:
字母代表的容錯(cuò)能力分別為:
L : 7%
M : 15%
Q : 25%
H : 30%
注意:
基本原則:
1蒋得、三個(gè)角上的“回”及“回”字周圍的底色不要?jiǎng)?br>
2级及、中間部分和不帶“回”字的一角是可以填圖片的(中間最好)
3、如果中間有小的“回”字额衙,能不變就不變饮焦,能少變就少變
4、盡可能放大二維碼后再添加圖片窍侧,不要添加圖片后放大
5县踢、生成時(shí)盡量選擇較高的糾錯(cuò)級(jí)別
所以再給qrFilter設(shè)置一個(gè)容錯(cuò)屬性:
[qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"];//設(shè)置二維碼的糾錯(cuò)水平,越高糾錯(cuò)水平越高伟件,可以污損的范圍越大
其實(shí)到這里二維碼顯示就完成了硼啤,通過(guò)imageWithCGImage
方法轉(zhuǎn)為UIImage用UIImageView顯示就可以。但是這樣顯示會(huì)有點(diǎn)模糊斧账,我們需要清晰化處理一下谴返,使二維碼更清楚,代碼如下:
CIImage *image = qrFilter.outputImage;
CGRect extent = CGRectIntegral(image.extent);
CGFloat scale = MIN(size.width / CGRectGetWidth(extent), size.width / CGRectGetHeight(extent));
size_t width = CGRectGetWidth(extent) * scale;
size_t height = CGRectGetHeight(extent) * scale;
//創(chuàng)建DeviceGray灰度色調(diào)空間
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
//創(chuàng)建bitmap
CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, colorSpace, (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);
CGColorSpaceRelease(colorSpace);
return [UIImage imageWithCGImage: scaledImage];
還有一種繪畫(huà)方法,也能達(dá)到相同效果咧织,代碼如下:
//上色
UIColor *onColor = [UIColor blackColor];
UIColor *offColor = [UIColor whiteColor];
CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor"
keysAndValues:
@"inputImage",qrFilter.outputImage,
@"inputColor0",[CIColor colorWithCGColor:onColor.CGColor],
@"inputColor1",[CIColor colorWithCGColor:offColor.CGColor],
nil];
CIImage *qrImage = colorFilter.outputImage;
//繪制
CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:qrImage fromRect:qrImage.extent];
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage);
UIImage *codeImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRelease(cgImage);
return codeImage;
得到效果圖如下:
??有一點(diǎn)非常有趣嗓袱,比如你封裝的格式越復(fù)雜二維碼密度越大,如果你封裝的只有數(shù)字习绢,比如@"111111",三個(gè)"回"字顯示的比較大渠抹,密度較小,自己體會(huì)!顯示的效果如下:
二逼肯、自定義顏色二維碼
由上面顯示的二維碼可知耸黑,一般二維碼都是黑白相間的格子組成,但有時(shí)我們需要個(gè)性化一點(diǎn)的二維碼篮幢,那就需要定制一個(gè)專屬顏色大刊,這里所用的方法就是遍歷像素, 改變像素點(diǎn)顏色,代碼如下:
//改變二維碼顏色
+ (UIImage *)createQRImageWithContent:(NSString *)content size:(CGSize)size red:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue{
UIImage *image = [self createQRImageWithContent:content size:size];
int imageWidth = image.size.width;
int imageHeight = image.size.height;
size_t bytesPerRow = imageWidth * 4;
uint32_t *rgbImageBuf = (uint32_t *)malloc(bytesPerRow * imageHeight);
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpaceRef, kCGBitmapByteOrder32Little|kCGImageAlphaNoneSkipLast);
CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage);
//遍歷像素, 改變像素點(diǎn)顏色
int pixelNum = imageWidth * imageHeight;
uint32_t *pCurPtr = rgbImageBuf;
for (int i = 0; i<pixelNum; i++, pCurPtr++) {
if ((*pCurPtr & 0xffffff00) < 0xd0d0d000) {
//將黑點(diǎn)變成自定義的顏色
uint8_t* ptr = (uint8_t*)pCurPtr;
ptr[3] = red*255;
ptr[2] = green*255;
ptr[1] = blue*255;
}else{
//將白點(diǎn)變成透明色三椿,如不需要變透明則屏蔽
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, colorSpaceRef,
kCGImageAlphaLast | kCGBitmapByteOrder32Little, dataProvider,
NULL, true, kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
UIImage *resultImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGContextRelease(context);
CGColorSpaceRelease(colorSpaceRef);
return resultImage;
}
void ProviderReleaseData(void * info, const void * data, size_t size) {
free((void *)data);
}
效果圖如下:
??細(xì)心的同學(xué)發(fā)現(xiàn)缺菌,用生成普通二維碼的時(shí)候所用的第二種繪制方法,改變二維碼顏色方法更簡(jiǎn)單搜锰,關(guān)鍵代碼是這兩種顏色:
UIColor *onColor = [UIColor blackColor];//黑點(diǎn)
UIColor *offColor = [UIColor whiteColor];//白點(diǎn)
你只需要把onColor
改為定制顏色就OK了伴郁,非常簡(jiǎn)單!
三蛋叼、帶logo的二維碼
我們?cè)谕饷婵吹降暮?bào)附帶的二維碼一般都會(huì)帶個(gè)logo焊傅,這樣又展示了公司的logo又使二維碼變的更加漂亮!如果logo不需要切圓角狈涮,使用drawInRect
就能實(shí)現(xiàn)狐胎,代碼如下:
+ (UIImage *)createQRImageWithContent:(NSString *)content size:(CGSize)size red:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue withLogo:(UIImage *)logo logoFrame:(CGRect)logoFrame{
UIImage *image = [self createQRImageWithContent:content size:size red:red green:green blue:blue];
//有 logo 則繪制 logo
if (logo != nil) {
UIGraphicsBeginImageContext(image.size);
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
[logo drawInRect:logoFrame];
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultImage;
}else{
return image;
}
}
效果圖如下:
??但如果我們需要切圓角而且設(shè)計(jì)的漂亮點(diǎn)的的話,則需要額外處理歌馍,首先處理logo圖片,分為五個(gè)步驟:
1.先對(duì)畫(huà)布進(jìn)行裁切
2.填充背景顏色
3.執(zhí)行繪制logo
4.添加并繪制白色邊框
5.白色邊框的基礎(chǔ)上進(jìn)行繪制黑色分割線
代碼如下:
+ (UIImage *)clipCornerRadius:(UIImage *)image withSize:(CGSize) size{
// 白色border的寬度
CGFloat outerWidth = size.width/15.0;
// 黑色border的寬度
CGFloat innerWidth = outerWidth/10.0;
// 設(shè)置圓角
CGFloat corenerRadius = size.width/5.0;
// 為context創(chuàng)建一個(gè)區(qū)域
CGRect areaRect = CGRectMake(0, 0, size.width, size.height);
UIBezierPath *areaPath = [UIBezierPath bezierPathWithRoundedRect:areaRect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(corenerRadius, corenerRadius)];
// 因?yàn)閁IBezierpath劃線是雙向擴(kuò)展的 初始位置就不會(huì)是(0握巢,0)
// origin position
CGFloat outerOrigin = outerWidth/2.0;
CGFloat innerOrigin = innerWidth/2.0 + outerOrigin/1.2;
CGRect outerRect = CGRectInset(areaRect, outerOrigin, outerOrigin);
CGRect innerRect = CGRectInset(outerRect, innerOrigin, innerOrigin);
// 外層path
UIBezierPath *outerPath = [UIBezierPath bezierPathWithRoundedRect:outerRect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(outerRect.size.width/5.0, outerRect.size.width/5.0)];
// 內(nèi)層path
UIBezierPath *innerPath = [UIBezierPath bezierPathWithRoundedRect:innerRect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(innerRect.size.width/5.0, innerRect.size.width/5.0)];
// 創(chuàng)建上下文
UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);{
// 翻轉(zhuǎn)context
CGContextTranslateCTM(context, 0, size.height);
CGContextScaleCTM(context, 1, -1);
// 1.先對(duì)畫(huà)布進(jìn)行裁切
CGContextAddPath(context, areaPath.CGPath);
CGContextClip(context);
// 2.填充背景顏色
CGContextAddPath(context, areaPath.CGPath);
UIColor *fillColor = [UIColor colorWithRed:0.85 green:0.85 blue:0.85 alpha:1];
CGContextSetFillColorWithColor(context, fillColor.CGColor);
CGContextFillPath(context);
// 3.執(zhí)行繪制logo
CGContextDrawImage(context, innerRect, image.CGImage);
// 4.添加并繪制白色邊框
CGContextAddPath(context, outerPath.CGPath);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, outerWidth);
CGContextStrokePath(context);
// 5.白色邊框的基礎(chǔ)上進(jìn)行繪制黑色分割線
CGContextAddPath(context, innerPath.CGPath);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
CGContextSetLineWidth(context, innerWidth);
CGContextStrokePath(context);
}CGContextRestoreGState(context);
UIImage *radiusImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return radiusImage;
}
經(jīng)過(guò)上面的代碼我們實(shí)現(xiàn)了白色邊框黑色分割線的logo,完成了對(duì)logo的處理松却,當(dāng)然你想設(shè)計(jì)自己的形式也是可以的暴浦。
處理好了logo,接下來(lái)就要把logo繪制到二維碼上了晓锻,一般頭像大小不能大于畫(huà)布的1/4 歌焦。因?yàn)檫@個(gè)大小之內(nèi)的不會(huì)遮擋二維碼的有效信息,代碼如下:
+ (UIImage *)imageWithQRImage:(UIImage *)qrImage logo:(UIImage *)logo logoSize:(CGSize)size{
BOOL opaque = 1.0;
// 獲取當(dāng)前設(shè)備的scale
CGFloat scale = [UIScreen mainScreen].scale;
// 創(chuàng)建畫(huà)布Rect
CGRect bgRect = CGRectMake(0, 0, size.width, size.height);
// 頭像大小不能大于畫(huà)布的1/4 (這個(gè)大小之內(nèi)的不會(huì)遮擋二維碼的有效信息)
CGFloat logoWidth = (size.width/4);
CGFloat logoHeight = logoWidth;
//調(diào)用一個(gè)新的切割繪圖方法(裁切頭像圖片為圓角带射,并添加bored 返回一個(gè)newimage)
logo = [self clipCornerRadius:logo withSize:CGSizeMake(logoWidth, logoHeight)];
// 設(shè)置頭像的位置信息
CGPoint position = CGPointMake(size.width/2, size.height/2);
CGRect logoRect = CGRectMake(position.x-(logoWidth/2), position.y-(logoHeight/2), logoWidth, logoHeight);
// 設(shè)置畫(huà)布信息
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);{// 開(kāi)啟畫(huà)布
// 翻轉(zhuǎn)context (畫(huà)布)
CGContextTranslateCTM(context, 0, size.height);
CGContextScaleCTM(context, 1, -1);
// 根據(jù) bgRect 用二維碼填充視圖
CGContextDrawImage(context, bgRect, qrImage.CGImage);
// 根據(jù)newAvatarImage 填充頭像區(qū)域
CGContextDrawImage(context, logoRect, logo.CGImage);
}CGContextRestoreGState(context);// 提交畫(huà)布
// 從畫(huà)布中提取圖片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 釋放畫(huà)布
UIGraphicsEndImageContext();
return image;
}
最終合成傳遞多參數(shù)的方法:
+ (UIImage *)createQRImageWithContent:(NSString *)content size:(CGSize)size red:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue withLogo:(UIImage *)logo{
UIImage *image = [self createQRImageWithContent:content size:size red:red green:green blue:blue];
//為空則返回
if (!logo) { return image;}
UIImage *resultImage = [self imageWithQRImage:image logo:logo logoSize:logo.size];
return resultImage;
}
該方法包含前面所介紹的三種樣式的二維碼同规,需要logo則傳logo,需要自定義顏色則傳rgb值窟社;效果圖如下(明顯比對(duì)logo不處理時(shí)好看):
??以上就是二維碼顯示的一般樣式處理!如有其它則特殊處理某部分绪钥,萬(wàn)變不離其宗灿里!學(xué)會(huì)了怎么生成,不如再學(xué)習(xí)下iOS--二維碼的掃描
聲明: 轉(zhuǎn)載請(qǐng)注明出處http://www.reibang.com/p/52abb62d0d39