中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

iOS實現高效裁剪圖片圓角算法教程

發布時間:2020-10-23 18:14:26 來源:腳本之家 閱讀:203 作者:國孩 欄目:移動開發

前言

項目有個需求:裁剪圖片,針對頭像,下面是要求:

 iOS實現高效裁剪圖片圓角算法教程

大家可以看到這張圖片的圓角已經去除,下面說說我在項目利用了兩種方式實現此裁剪以及查看技術文檔發現更高效裁剪方式,下面一一講解:看下來大約需要15-20分鐘。

在公共類中Util類中創建類方法

1.CGContext裁剪

//CGContext裁剪
+ (UIImage *)CGContextClip:(UIImage *)img cornerRadius:(CGFloat)c;

實現該方法:

// CGContext 裁剪
+ (UIImage *)CGContextClip:(UIImage *)img cornerRadius:(CGFloat)c{
 int w = img.size.width * img.scale;
 int h = img.size.height * img.scale;
 UIGraphicsBeginImageContextWithOptions(CGSizeMake(w, h), false, 1.0);
 CGContextRef context = UIGraphicsGetCurrentContext();
 CGContextMoveToPoint(context, 0, c);
 CGContextAddArcToPoint(context, 0, 0, c, 0, c);
 CGContextAddLineToPoint(context, w-c, 0);
 CGContextAddArcToPoint(context, w, 0, w, c, c);
 CGContextAddLineToPoint(context, w, h-c);
 CGContextAddArcToPoint(context, w, h, w-c, h, c);
 CGContextAddLineToPoint(context, c, h);
 CGContextAddArcToPoint(context, 0, h, 0, h-c, c);
 CGContextAddLineToPoint(context, 0, c);
 CGContextClosePath(context);
 
 // 先裁剪 context,再畫圖,就會在裁剪后的 path 中畫
 CGContextClip(context);
 [img drawInRect:CGRectMake(0, 0, w, h)]; // 畫圖
 CGContextDrawPath(context, kCGPathFill);
 UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();
 
 return ret;
}

在該需要的地方調用如下:

[Util CGContextClip:image cornerRadius:radius];

2.UIBezierPath 裁剪

在Util.h類中聲明

//UIBezierPath 裁剪
+ (UIImage *)UIBezierPathClip:(UIImage *)img cornerRadius:(CGFloat)c;

在Util.m實現方法

//UIBezierPath 裁剪
+ (UIImage *)UIBezierPathClip:(UIImage *)img cornerRadius:(CGFloat)c{
 int w = img.size.width * img.scale;
 int h = img.size.height * img.scale;
 CGRect rect = CGRectMake(0, 0, w, h);
 UIGraphicsBeginImageContextWithOptions(CGSizeMake(w, h), false, 1.0);
 [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:c] addClip];
 [img drawInRect:rect];
 
 UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();
 return ret;
}

3.空域處理的辦法,寫個裁剪圓角的算法

對于圖像上的一個點(x, y),判斷其在不在圓角矩形內,在的話 alpha 是原值,不在的話 alpha 設為 0 即可

iOS實現高效裁剪圖片圓角算法教程 

遍歷所有像素,判斷每個像素在不在4個圓的圓內就行了,4個角,每個角有一個四分之一的圓。

一個優化就是,我不需要遍歷全部的像素就能裁出圓角,只需要考慮類似左下角三角形的區域就行了,左下,左上,右上,右下,一共4個三角形區域(另外3個圖中沒畫出),for循環的時候,就循環這個4個三角形區域就行了。

所以對于一幅 w * h 的圖像,設圓角大小為 n,n <= min(w, h) / 2,其復雜度為 O(n) = 2(n^2),最壞的情況計算量也不會超過 wh / 2。

對于一個像素點(x, y),判斷其在不在圓內的公式:
如果  (x-cx)^2 + (y-cy)^2 <= r^2  就表示點 (x, y) 在圓內,反之不在。通過測試:此算法效率可以提高幾倍之上(時間)

在Util.h中聲明:

+ (UIImage *)dealImage:(UIImage *)img cornerRadius:(CGFloat)c

在Util.m中實現:

+ (UIImage *)dealImage:(UIImage *)img cornerRadius:(CGFloat)c {
 // 1.CGDataProviderRef 把 CGImage 轉 二進制流
 CGDataProviderRef provider = CGImageGetDataProvider(img.CGImage);
 void *imgData = (void *)CFDataGetBytePtr(CGDataProviderCopyData(provider));
 int width = img.size.width * img.scale;
 int height = img.size.height * img.scale;
 
 // 2.處理 imgData
// dealImage(imgData, width, height);
 cornerImage(imgData, width, height, c);
 
 // 3.CGDataProviderRef 把 二進制流 轉 CGImage
 CGDataProviderRef pv = CGDataProviderCreateWithData(NULL, imgData, width * height * 4, releaseData);
 CGImageRef content = CGImageCreate(width , height, 8, 32, 4 * width, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast, pv, NULL, true, kCGRenderingIntentDefault);
 UIImage *result = [UIImage imageWithCGImage:content];
 CGDataProviderRelease(pv); // 釋放空間
 CGImageRelease(content);
 
 return result;
}

void releaseData(void *info, const void *data, size_t size) {
 free((void *)data);
}

// 在 img 上處理圖片, 測試用
void dealImage(UInt32 *img, int w, int h) {
 int num = w * h;
 UInt32 *cur = img;
 for (int i=0; i<num; i++, cur++) {
 UInt8 *p = (UInt8 *)cur;
 // RGBA 排列
 // f(x) = 255 - g(x) 求負片
 p[0] = 255 - p[0];
 p[1] = 255 - p[1];
 p[2] = 255 - p[2];
 p[3] = 255;
 }
}

// 裁剪圓角
void cornerImage(UInt32 *const img, int w, int h, CGFloat cornerRadius) {
 CGFloat c = cornerRadius;
 CGFloat min = w > h ? h : w;
 
 if (c < 0) { c = 0; }
 if (c > min * 0.5) { c = min * 0.5; }
 
 // 左上 y:[0, c), x:[x, c-y)
 for (int y=0; y<c; y++) {
 for (int x=0; x<c-y; x++) {
  UInt32 *p = img + y * w + x; // p 32位指針,RGBA排列,各8位
  if (isCircle(c, c, c, x, y) == false) {
  *p = 0;
  }
 }
 }
 // 右上 y:[0, c), x:[w-c+y, w)
 int tmp = w-c;
 for (int y=0; y<c; y++) {
 for (int x=tmp+y; x<w; x++) {
  UInt32 *p = img + y * w + x;
  if (isCircle(w-c, c, c, x, y) == false) {
  *p = 0;
  }
 }
 }
 // 左下 y:[h-c, h), x:[0, y-h+c)
 tmp = h-c;
 for (int y=h-c; y<h; y++) {
 for (int x=0; x<y-tmp; x++) {
  UInt32 *p = img + y * w + x;
  if (isCircle(c, h-c, c, x, y) == false) {
  *p = 0;
  }
 }
 }
 // 右下 y~[h-c, h), x~[w-c+h-y, w)
 tmp = w-c+h;
 for (int y=h-c; y<h; y++) {
 for (int x=tmp-y; x<w; x++) {
  UInt32 *p = img + y * w + x;
  if (isCircle(w-c, h-c, c, x, y) == false) {
  *p = 0;
  }
 }
 }
}

// 判斷點 (px, py) 在不在圓心 (cx, cy) 半徑 r 的圓內
static inline bool isCircle(float cx, float cy, float r, float px, float py) {
 if ((px-cx) * (px-cx) + (py-cy) * (py-cy) > r * r) {
 return false;
 }
 return true;
}

// 其他圖像效果可以自己寫函數,然后在 dealImage: 中調用 otherImage 即可
void otherImage(UInt32 *const img, int w, int h) {
 // 自定義處理
}

上面是三種方式,可以解決圖片裁剪的需求,

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

汤原县| 邳州市| 天气| 龙井市| 丹江口市| 象山县| 和平区| 双牌县| 龙江县| 紫金县| 张北县| 婺源县| 改则县| 新乐市| 临安市| 清镇市| 北辰区| 霍邱县| 嘉禾县| 盐源县| 易门县| 迭部县| 泽库县| 白河县| 海口市| 玉环县| 北京市| 积石山| 水富县| 石首市| 报价| 冕宁县| 嘉定区| 乐亭县| 五指山市| 安庆市| 合作市| 哈尔滨市| 湟中县| 七台河市| 兴宁市|