亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS 定制多樣式二維碼

2020-07-26 02:52:24
字體:
來源:轉載
供稿:網友

二維碼/條形碼是按照某種特定的幾何圖形按一定規律在平臺(一維/二維方向上)分布的黑白相間的圖形紀錄符號信息。使用若干個與二進制對應的幾何形體來表示文字數值信息。

最常見的二維碼功能包括信息獲取、網站跳轉、電商交易、手機支付等等,其擁有密度小、信息容量大、容錯能力強、成本低、制作難度低等優點。在移動開發中,二維碼的地位也越來越重要,掌握二維碼的基本操作是重要的本領之一。

在iOS7之后,蘋果自身集成了二維碼的生成和讀取功能。生成二維碼包括以下步驟

  • 導入CoreImage/CoreImage.h頭文件
  • 使用CIFilter濾鏡類生成二維碼
  • 對生成的二維碼進行加工,使其更清晰

除了上述三個步驟之外,我們還可以對二維碼進行進一步的拓展處理

  • 自定義二維碼圖案顏色
  • 在二維碼中心插入圓角小圖片
  • 在圓角圖片下面加上一層圓角白色圖片

二維碼生成

碼農們生產代碼的同時永遠不要忘記盡可能的復用,那么為了實現這種目的,本文的代碼通過類別拓展UIImage的方法來完成。我們先聲明并實現一個類方法用來接收二維碼存儲數據以及二維碼尺寸的方法:

+ (UIImage *)imageOfQRFromURL: (NSString *)networkAddress codeSize: (CGFloat)codeSize {  if (!networkAddress|| (NSNull *)networkAddress == [NSNull null]) {     return nil;    }  codeSize = [self validateCodeSize: codeSize];   CIImage * originImage = [self createQRFromAddress: networkAddress];  UIImage * result = [UIImage imageWithCIImage: originImage];   return result;}

在上面的代碼里面,我們總共做了四件事情:驗證存儲信息的有效性;驗證二維碼尺寸的合理大??;使用存儲信息生成二維碼;將二維碼轉成UIImage返回。這些方法的實現分別如下:

/*! 驗證二維碼尺寸合法性*/+ (CGFloat)validateCodeSize: (CGFloat)codeSize{  codeSize = MAX(160, codeSize);  codeSize = MIN(CGRectGetWidth([UIScreen mainScreen].bounds) - 80, codeSize);  return codeSize;}/*! 利用系統濾鏡生成二維碼圖*/+ (CIImage *)createQRFromAddress: (NSString *)networkAddress{  NSData * stringData = [networkAddress dataUsingEncoding: NSUTF8StringEncoding];  CIFilter * qrFilter = [CIFilter filterWithName: @"CIQRCodeGenerator"];  [qrFilter setValue: stringData forKey: @"inputMessage"];  [qrFilter setValue: @"H" forKey: @"inputCorrectionLevel"];  return qrFilter.outputImage;}/! 驗證二維碼尺寸合法性/- (CGFloat)validateCodeSize: (CGFloat)codeSize{  codeSize = MAX(160, codeSize);  codeSize = MIN(CGRectGetWidth([UIScreen mainScreen].bounds) - 80, codeSize);  return codeSize;}/! 利用系統濾鏡生成二維碼圖/- (CIImage *)createQRFromAddress: (NSString *)networkAddress{  NSData * stringData = [networkAddress dataUsingEncoding: NSUTF8StringEncoding];  CIFilter * qrFilter = [CIFilter filterWithName: @"CIQRCodeGenerator"];  [qrFilter setValue: stringData forKey: @"inputMessage"];  [qrFilter setValue: @"H" forKey: @"inputCorrectionLevel"];  return qrFilter.outputImage;}

ps:對于CIFilter想要更進一步了解,可以在xcode中使用快捷鍵shift+command+0打開文檔,然后搜索core image filter reference獲取更多濾鏡的使用方法,這些濾鏡可以用來實現類似美圖秀秀的修圖功能。

上面的代碼生成了一個粗略的二維碼圖,我們需要對圖片再進行一次處理,使其清晰化。因為,我們需要另外一個類別方法:

/! 對圖像進行清晰化處理/- (UIImage *)excludeFuzzyImageFromCIImage: (CIImage *)image size: (CGFloat)size{  CGRect extent = CGRectIntegral(image.extent);  CGFloat scale = MIN(size / CGRectGetWidth(extent), size / CGRectGetHeight(extent));  size_t width = CGRectGetWidth(extent) * scale;   size_t height = CGRectGetHeight(extent) * scale;  //創建灰度色調空間  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();  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);  CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);  CGContextRelease(bitmapRef);  CGImageRelease(bitmapImage);  CGColorSpaceRelease(colorSpace);  return [UIImage imageWithCGImage: scaledImage];}

那么這時候,我們把+(UIImage *)imageOfQRFromURL: codeSize:的最后改成

UIImage * result =[self excludeFuzzyImageFromCIImage: originImage size: codeSize];

示例完成后生成的二維碼效果圖如下:

二維碼拓展

單一的黑白色二維碼并不一定總能滿足開發的需求或者說領導的需求。好比現在的應用很多功能界面上都在朝著微信學習,這就包括了更多色彩,更多樣式的二維碼。本文將從顏色、二維碼中心小圖案這兩點入手講解如何制作類似微信生成我的二維碼的樣式。

自定義二維碼顏色的實現思路是,遍歷生成的二維碼的像素點,將其中為白色的像素點填充為透明色,非白色則填充為我們自定義的顏色。但是,這里的白色并不單單指純白色,rgb值高于一定數值的灰色我們也可以視作白色處理。在這里我對白色的定義為rgb值高于0xd0d0d0的顏色值為白色,這個值并不是確定的,大家可以自己設置。基于顏色的設置,我們將原有生成二維碼的方法接口改成這樣:

+ (UIImage *)imageOfQRFromURL: (NSString *)networkAddress codeSize: (CGFloat)codeSize red: (NSUInteger)red green: (NSUInteger)green blue: (NSUInteger)blue {   if (!networkAddress || (NSNull *)networkAddress == [NSNull null]) { return nil; }  /** 顏色不可以太接近白色*/  NSUInteger rgb = (red << 16) + (green << 8) + blue;  NSAssert((rgb & 0xffffff00) <= 0xd0d0d000, @"The color of QR code is two close to white color than it will diffculty to scan");  codeSize = [self validateCodeSize: codeSize];   CIImage * originImage = [self createQRFromAddress: networkAddress];  UIImage * progressImage = [self excludeFuzzyImageFromCIImage: originImage size: codeSize];   //到了這里二維碼已經可以進行掃描了  UIImage * effectiveImage = [self imageFillBlackColorAndTransparent: progressImage red: red green: green blue: blue]; //進行顏色渲染后的二維碼  return effectiveImage;}

相較于前面的代碼,多了兩個步驟:判斷rgb的有效值;對二維碼進行顏色渲染。顏色渲染的過程包括獲取圖像的位圖上下文、像素替換、二進制圖像轉換等操作,具體代碼如下:

/*! 對生成二維碼圖像進行顏色填充*/+ (UIImage *)imageFillBlackColorAndTransparent: (UIImage *)image red: (NSUInteger)red green: (NSUInteger)green blue: (NSUInteger)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, (CGRect){(CGPointZero), (image.size)}, image.CGImage); //遍歷像素 int pixelNumber = imageHeight * imageWidth; [self fillWhiteToTransparentOnPixel: rgbImageBuf pixelNum: pixelNumber red: red green: green blue: blue]; CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow, ProviderReleaseData); CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight, 8, 32, bytesPerRow, colorSpace, kCGImageAlphaLast | kCGBitmapByteOrder32Little, dataProvider, NULL, true, kCGRenderingIntentDefault); UIImage * resultImage = [UIImage imageWithCGImage: imageRef];  CGImageRelease(imageRef); CGColorSpaceRelease(colorSpace); CGContextRelease(context); return resultImage;}/! 遍歷所有像素點進行顏色替換/+ (void)fillWhiteToTransparentOnPixel: (uint32_t *)rgbImageBuf pixelNum: (int)pixelNum red: (NSUInteger)red green: (NSUInteger)green blue: (NSUInteger)blue {uint32_t * pCurPtr = rgbImageBuf;for (int i = 0; i < pixelNum; i++, pCurPtr++) {    if ((*pCurPtr & 0xffffff00) < 0xd0d0d000) {      uint8_t * ptr = (uint8_t *)pCurPtr;      ptr[3] = red;      ptr[2] = green;      ptr[1] = blue;    } else {      //將白色變成透明色      uint8_t * ptr = (uint8_t *)pCurPtr;      ptr[0] = 0;    }  }}void ProviderReleaseData(void * info, const void * data, size_t size) {  free((void *)data);}

ps:在修改代碼之前,應該想清楚是否需要刪除原有代碼。類似這種二維碼的擴展,舊的二維碼生成接口可以留下來,然后在其中調用多參數的全能構造器Designated Initializer。

這時候距離微信還差一小步,我們要在二維碼的中心位置插入我們的小頭像,最直接的方式是加載完我們的頭像后,直接drawInRect:這種實現方法是正確的,但是在我們畫上去之前,我們還需要對圖像進行圓角處理。(省事的可能直接用imageView加載頭像,然后設置頭像的cornerRadius,這個也能實現效果)。

到了這個時候,我們需要一個更多參數的二維碼生成方法接口了,這次新增的參數應該包括插入圖片、圓角半徑這些參數,因此方法如下:

+ (UIImage *)imageOfQRFromURL: (NSString *)networkAddress codeSize: (CGFloat)codeSize red: (NSUInteger)red green: (NSUInteger)green blue: (NSUInteger)blue insertImage: (UIImage *)insertImage roundRadius: (CGFloat)roundRadius {  if (!networkAddress || (NSNull *)networkAddress == [NSNull null]) { return nil; }  /** 顏色不可以太接近白色*/  NSUInteger rgb = (red << 16) + (green << 8) + blue;  NSAssert((rgb & 0xffffff00) <= 0xd0d0d000, @"The color of QR code is two close to white color than it will diffculty to scan");  codeSize = [self validateCodeSize: codeSize];  CIImage * originImage = [self createQRFromAddress: networkAddress];  UIImage * progressImage = [self excludeFuzzyImageFromCIImage: originImage size: codeSize];   //到了這里二維碼已經可以進行掃描了  UIImage * effectiveImage = [self imageFillBlackColorAndTransparent: progressImage red: red green: green blue: blue]; //進行顏色渲染后的二維碼  return [self imageInsertedImage: effectiveImage insertImage: insertImage radius: roundRadius];}

這次的生成方法同樣也只需要進行一次額外的調用方法操作,在插入圖片的時候我們需要注意,類似微信的圖中圖二維碼中間的小頭像是有一個圓角的白色邊緣的,這個邊緣的加入讓頭像顯示的更加自然。那么要完成這個效果,我額外在項目中加入了一張白色背景的小圖,同樣對這張圖片進行圓角化處理,然后加在頭像的下面。作為頭像下方的白色背景圖像尺寸應該大于頭像圖。制作畫中畫效果的具體實現如下:

/! 在二維碼原圖中心位置插入圓角圖像/+ (UIImage *)imageInsertedImage: (UIImage *)originImage insertImage: (UIImage *)insertImage radius: (CGFloat)radius{  if (!insertImage) { return originImage; }  insertImage = [UIImage imageOfRoundRectWithImage: insertImage size: insertImage.size radius: radius];  UIImage * whiteBG = [UIImage imageNamed: @"whiteBG"];  whiteBG = [UIImage imageOfRoundRectWithImage: whiteBG size: whiteBG.size radius: radius];  //白色邊緣寬度  const CGFloat whiteSize = 2.f;  CGSize brinkSize = CGSizeMake(originImage.size.width / 4, originImage.size.height / 4);  CGFloat brinkX = (originImage.size.width - brinkSize.width) * 0.5;  CGFloat brinkY = (originImage.size.height - brinkSize.height) * 0.5;  CGSize imageSize = CGSizeMake(brinkSize.width - 2 * whiteSize, brinkSize.height - 2 * whiteSize);  CGFloat imageX = brinkX + whiteSize;  CGFloat imageY = brinkY + whiteSize;  UIGraphicsBeginImageContext(originImage.size);  [originImage drawInRect: (CGRect){ 0, 0, (originImage.size) }];  [whiteBG drawInRect: (CGRect){ brinkX, brinkY, (brinkSize) }];  [insertImage drawInRect: (CGRect){ imageX, imageY, (imageSize) }];  UIImage * resultImage = UIGraphicsGetImageFromCurrentImageContext();  UIGraphicsEndImageContext();  return resultImage;}- (UIImage *)imageOfRoundRectWithImage: (UIImage *)image size: (CGSize)size radius: (CGFloat)radius{  if (!image) { return nil; }  const CGFloat width = size.width;  const CGFloat height = size.height;  radius = MAX(5.f, radius);  radius = MIN(10.f, radius);  UIImage * img = image;   CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();  CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedFirst);  CGRect rect = CGRectMake(0, 0, width, height);  //繪制圓角  CGContextBeginPath(context);  addRoundRectToPath(context, rect, radius, img.CGImage);  CGImageRef imageMasked = CGBitmapContextCreateImage(context);  img = [UIImage imageWithCGImage: imageMasked];  CGContextRelease(context);  CGColorSpaceRelease(colorSpace);  CGImageRelease(imageMasked);  return img;}

ps:圖像繪制圓角是通過在圖像上下文中畫出圓角矩形的路徑,然后進行裁剪,這樣就能實現圖片的圓角化。

在代碼中,對中心位置的頭像限制尺寸為二維碼的四分之一,這個尺寸下的頭像不失清晰度,而且圖片尺寸也不至于遮蓋了二維碼的存儲數據。上面的方法都可以在頭文件中開發方法接口使用,這將實現這些代碼的復用。另外,所有本文中寫到的生成二維碼的接口都應該在頭文件中聲明,并且在其實現中調用全能方法(不應當僅僅是構造器需要遵循Designated Initializer的原則):

+ (UIImage *)imageOfQRFromURL: (NSString *)networkAddress {  return [self imageOfQRFromURL: networkAddress codeSize: 100.0f red: 0 green: 0 blue: 0 insertImage: nil roundRadius: 0.f];}

以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持武林網!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久亚洲私人国产精品va| 2019亚洲日韩新视频| 国产在线不卡精品| 精品视频一区在线视频| 国产成人涩涩涩视频在线观看| 久久免费精品日本久久中文字幕| 亚洲a∨日韩av高清在线观看| 欧美视频在线观看免费网址| 久久五月天色综合| 成人免费观看a| 亚洲自拍在线观看| 亚洲成人动漫在线播放| 91av在线精品| 亚洲区bt下载| 欧亚精品在线观看| 国产视频精品久久久| 欧美第一淫aaasss性| 欧美做受高潮电影o| 日本欧美爱爱爱| www.日韩欧美| 欧美一区二区三区……| 伊人亚洲福利一区二区三区| 久久久人成影片一区二区三区观看| 永久免费看mv网站入口亚洲| 日韩欧美中文在线| 欧美风情在线观看| 欧美精品18videosex性欧美| 精品香蕉一区二区三区| 亚洲精品少妇网址| 成人午夜激情网| 欧美另类精品xxxx孕妇| 国产亚洲激情视频在线| 久久伊人精品天天| 国产精品久久久久不卡| 国产精品2018| 国模吧一区二区三区| 午夜精品久久久久久久99黑人| 亚洲欧美日韩高清| 亚洲人成绝费网站色www| 日韩av片电影专区| 日韩免费av在线| 亚洲激情视频在线播放| 日韩中文字幕在线观看| 91免费的视频在线播放| 欧美精品久久一区二区| 日韩久久精品成人| 久久精品视频免费播放| 日韩一区二区久久久| 亚洲福利视频二区| 久久久亚洲欧洲日产国码aⅴ| 久久精品美女视频网站| 欧美精品18videosex性欧美| 亚洲国产日韩一区| 欧美俄罗斯乱妇| 福利精品视频在线| 久久精品电影一区二区| 九九久久精品一区| 日本成人激情视频| 91精品国产91久久久久久久久| 97视频色精品| 久久久久五月天| 亚洲精品国产精品自产a区红杏吧| 国产成人一区二区三区小说| 国产综合在线看| 日韩在线观看免费全集电视剧网站| 国产亚洲人成a一在线v站| 国产日韩专区在线| 国产一区视频在线播放| 久久精品视频在线观看| 日韩精品在线观| 国产福利视频一区二区| 精品久久久久久久久久久久| 欧美成人精品影院| 日韩精品视频中文在线观看| 亚洲精品久久久久久久久久久| 亚洲精品国产成人| 国产精品美女999| 日韩在线视频免费观看| 欧美黑人xxxx| 欧美精品videos另类日本| 欧美成人在线影院| 久久成人精品视频| 中文字幕在线观看日韩| 亚洲最新中文字幕| 亚洲精品免费在线视频| 清纯唯美亚洲激情| 国产精品极品美女在线观看免费| 97久久超碰福利国产精品…| 日韩欧美亚洲国产一区| 亚洲精品大尺度| 国产激情999| 国产精品夜间视频香蕉| 亚洲电影第1页| 久久久久久久999精品视频| 欧美一区三区三区高中清蜜桃| 亚洲成色777777女色窝| 久久久久国色av免费观看性色| 欧美日韩亚洲国产一区| 亚洲精品电影久久久| 精品国产欧美一区二区三区成人| 欧美一级免费视频| 国产精品网站视频| 国产精品美女视频网站| 欧美重口另类videos人妖| 51精品在线观看| 国产精品久久999| 国产精品成av人在线视午夜片| 精品国产一区二区三区久久| 欧美色视频日本高清在线观看| 色樱桃影院亚洲精品影院| 国产91精品高潮白浆喷水| 国产精品普通话| 亚洲国产成人精品久久| 91精品国产高清自在线| 欧美国产日韩一区| 91精品啪在线观看麻豆免费| 97av在线视频免费播放| 国产成人精品优优av| 久久亚洲精品小早川怜子66| 91av在线播放视频| 久久视频在线视频| 国产综合在线视频| 91av视频在线播放| 992tv成人免费影院| 性色av一区二区三区免费| 91精品91久久久久久| 国产免费成人av| 亚洲欧美国产视频| 欧美极品美女视频网站在线观看免费| 欧美大码xxxx| 久久久www成人免费精品| 黑人极品videos精品欧美裸| 亚洲欧美www| 久久免费高清视频| 韩国欧美亚洲国产| 欧美成人国产va精品日本一级| 欧美国产日韩在线| 精品一区二区三区四区在线| 欧美久久精品午夜青青大伊人| 奇米成人av国产一区二区三区| 97久久精品人人澡人人爽缅北| 热99在线视频| 精品亚洲一区二区三区四区五区| 欧美噜噜久久久xxx| 亚洲福利视频久久| 欧美一级视频免费在线观看| 精品视频久久久| 国产精品久久久久av免费| 国产成人亚洲综合91精品| 96sao精品视频在线观看| 久久久久久亚洲精品| 国内外成人免费激情在线视频网站| 欧美激情综合色| 国产精品入口日韩视频大尺度| 国产精品视频专区| 日韩av手机在线观看| 亚洲日本中文字幕| 一区二区在线免费视频| 91精品久久久久久久久久久| 曰本色欧美视频在线| 这里只有精品视频| 九九热这里只有在线精品视| 国产精品一区二区三区免费视频| 亚洲影院色无极综合|